I have a parent model Account with multiple subclasses using STI. I want to associate another model Transaction using a belongs_to relationship to Account. The referenced account could be either an Asset or a Liability.
class Account < ActiveRecord::Base end
class Asset < Account end
class Liability < Account end
My transaction model belongs_to Account
class Transaction < ActiveRecord::Base
belongs_to :account #Either an Asset or Liability model
end
I want to be able to set a transaction's account to either an Asset or a Liability. However, I get a TypeMismatch error when I set the transaction's account to an Asset or Liablity since it isn't the parent class Account.
Note: I think this could be solved using polymorphism on the belongs_to association, but it seems unnecessary to specify the class in a type column when the referenced models all use the same underlying table.
It turns out that this code works as is. You don't need to specify a polymorphic type on the associated model to the STI model.
The type mismatch error I was receiving was because my STI base class was actually "Account::Base" and I simply had "Account" as the class name.
Related
I have 3 models
class Company < ActiveRecord::Base
has_many : CompanyAccount
has_many : CompanyContact
end
class CompanyContact < ActiveRecord::Base
belongs_to : Company
end
class CompanyAccount < ActiveRecord::Base
belongs_to : Company
end
As both the CompanyAccount and CompanyContact models belong to the Company model, they have a similar "company_id" field. I have retrieved some Accounts through a query:
#CompanyAccounts = CompanyAccount.where.not(balance:nil)
Now, using the common company_id field I am trying to retrieve all the data from my CompanyContacts table that belong to the same Company associated with the CompanyAccounts I queried above (in other words, I am trying to get the rows which have the same company_id). I have made several attempts using "joins" but everything failed so far. Could anyone give me what would be the appropriate syntax in this context? Thanks.
First things first, please pay attention to proper Ruby naming conventions. Ruby classes and modules should use CamelCase while symbols, methods, and variables should all use snake_case. Given this, I would re-write your models as follows
class Company < ActiveRecord::Base
has_many: company_accounts
has_many: company_contacts
end
class CompanyContact < ActiveRecord::Base
belongs_to: company
end
class CompanyAccount < ActiveRecord::Base
belongs_to: company
end
Now, onto your question. I would use includes to eager load the associated company and it's associated contacts. For example
#company_accounts = CompanyAccount.includes(company: :company_contacts).where.not(balance: nil)
What this will do is for each company account with a balance, it will load it's associated company and the company's associated contacts into memory so that you can access it
#company_accounts.each do |account|
# access to the company
account.company
# access to the company's contacts
account.company.contacts
end
Hope this helps.
I have been reading about Active Record Associations on RailGuides and I have found it very informative but I definitely need help with understanding some of the choices. Still learning.
I have a Client model with the following attributes:
name
birth_date
address1
etc
Then a Contract model with these attributes:
auth_num
start_date
end_date
client_id .... I think I need this here for the new contract form
Also, a Code model with these attributes:
code_name
status
description
I have a join table ClientLines with these attributes:
Contract_id
Client_id
And a join table CodeLines with these attributes:
Contract_id
Code_id
Client_id
Units_Alloc ... each contract might use a combination of codes some of which are
the same in other contracts but they have different number of units
allocated.
I am tempted to use the Polymorphic association because the Contract model is associated with the Client Model and the Code Model, but I am not confident enough to go ahead and set this up without first checking if someone is willing to give me some guidance on the examples I have listed?
My hope for guidance rests around these questions.
Is the polymorphic association the best choice for the example of models I have listed above?
Since Contracts use different combinations of Codes, but some of the Codes are the same in other Contracts with the only difference being the number of units allocated, do I have units allocated in the correct table? (Essentially I do not know where to put units alloc?)
When I set up the data-entry form such that I can enter in new contracts which will pull in specific attributes from the client table and code table, is it appropriate to have Client_id listed as one of the attributes of the Contract model and of course the units alloc attribute still looms large in my mind as a problem, where do I pull it from?
Any help or pointers would be most helpful.
Thanks.
Well, I'll give it a try :)
I understand, that we come from a Contract, that is a signed by one client and is about some "Codes". So it can go like this:
class Contract < ActiveRecord::Base
has_one :client
has_many :codes
end
class Client < ActiveRecord::Base
belongs_to :contract
end
class Code < ActiveRecord::Base
belongs_to :contract
end
Where you store contract_id in clients table and in codes table. Then you can do AR operations like:
contract = Contact.find_by_auth_num(1234)
contract.client #gets you the client
contract.codes #gets you contracted codes
contract.codes.count #gets you number of contracted codes
Or if you want it more sophisticated you can change the relation to
class Contract < ActiveRecord::Base
has_one :client
has_many :contract_codes
has_many :codes, :through => :contract_codes
end
class Code < ActiveRecord::Base
has_many :contract_codes
has_many :contracts, :through => :contract_codes
end
with intermediate model of
ContractCode < ActiveRecord::Base
belongs_to :code
belongs_to :contract
end
where you can store number of codes in a special column. Of course, all these declarations has to be backed up by proper migrations :) Did I clear things a bit?
I'm trying to make a basic checkout page, and here's what I have so far:
The checkout is hosted off of transactions#new, and the form is built off of a new Transaction object. Transaction has a number of nested models underneath it:
class Transaction < ActiveRecord::Base
# ...
accepts_nested_attributes_for :user, :shipping_address, :products
# ...
end
User, Product, and Location (Shipping Address) can be persisted when you arrive at the checkout page, depending on the user flow. Product is always persisted upon arriving at the checkout page.
This setup works for me so far except on the failure cases. I've been trying to re-create the new Transaction record (with the previously entered in user info) to display the appropriate error messages, and I had tried doing this in my controller:
class TransactionsController < ApplicationController
def new
#transaction = Transaction.new
end
def create
#transaction = Transaction.new params[:transaction]
# ...
end
end
But I'm getting this error:
ActiveRecord::RecordNotFound in TransactionsController#create
Couldn't find Product with ID=1 for Transaction with ID=
Request Parameters
{"utf8"=>"✓", "authenticity_token"=>"blahblahblah",
"transaction"=>{"products_attributes"=>{"0"=>{"id"=>"1",
"quantity"=>"1"}}}}
Does anyone know what's up with this? Let me know if you need anymore info about my setup here... tried to pare this issue down to the bare essentials...
class Transaction < ActiveRecord::Base
has_many :product_transactions
has_many :products, :through => :product_transactions
end
and
class Product < ActiveRecord::Base
has_many :product_transactions
has_many :transactions, :through => :product_transactions
end
and
class ProductTransaction < ActiveRecord::Base
belongs_to :transaction
belongs_to :product
end
So, the reason you're getting that error is because you're supplying an id with products_attributes, since you're using accepts_nested_attributes_for the product with that id HAS to already be in the association. This is because the products_attributes= method is expecting to either create or modify the records in the products association.
Since the Product is already persisted and you're just trying to create the ProductTransaction you would need change your accepts_nested_attributes_for to include :product_transactions instead.
This part of your question threw me off
User, Product, and Location (Shipping Address) can be persisted when you arrive at the checkout page, depending on the user flow. Product is always persisted upon arriving at the checkout page.
I don't know if you need to be able to define a product... But if you need to create a Product on the checkout page it would make more sense to define it in the context of a ProductTransaction (ie. ProductTransaction accepts product_attributes or product_id) instead of the context of a Transaction.
I made a relationship with the three models using has_many :through:
class Curriculum class < ActiveRecord::Base
has_many :interests
has_many :vacancies,: through => :interests
end
class Vacancy class < ActiveRecord::Base
has_many :interests
has_many :resumes,: through => :interests
end
class Interest < ActiveRecord:: Base
belongs_to :vacancy
belongs_to :curriculum
end
And to create curriculum and vacancy, I create them by administrative, i need to know how can i create the interest to the id of the vacancy, and how it will be logged on the system I have to get the id of it and make the relationship in creating a new bank interest. I wonder how I can program it to do so, and I wonder how the controller will get the create action, and what better way to do this.
First, try to read the whole "Guide to Rails on Associations", especially the part about has_many :through. Then check your schema if your db is migrated and contains for the table interests the necessary foreign keys to curriculums and vacancies called curriculum_id and vacancy_id.
If that is all in place, the following code will create the relationship between two objects:
#curr = Curriculum.find(1)
#vac = Vacancy.find(1)
#curr.interests << #vac
#curr.save
The last two lines creates an interest between #curr and #vac and store that on the database. So you should not use IDs and handle them directly, but work with objects instead.
The second part now is to provide a UI to allow the definition (and removal) of interests between curricula and vacancies. The base flow here is:
You have one curriculum in focus.
You have a link to add / remove curricula.
The view that opens shows a list of possible vacancies, where every vacancy has a checkbox.
By selecting (or deselecting) the check boxes, the IDs of the vacancies will be held in the params of the request sent to the controller.
See the (older) podcast Railscast #52 how to do that in a similar context. Or see the example for has_many :through with checkboxes.
An alternative way would be to use JQuery autocomplete, and add so interests one-by-one. See the nice podcast Railscast #258 which uses JQuery Tokeninput for that.
I think this is what your looking for:
HABTM Checkboxes
That's the best way to use an Has and Belongs to many association.
Suppose I have the following model relationship:
class Player < ActiveRecord::Base
has_many :cards
end
class Card < ActiveRecord::Base
belongs_to :player
end
I know from this question that Rails will return me a copy of the object representing a database row, meaning that:
p = Player.find(:first)
c = p.cards[0]
c.player.object_id == p.object_id # => false
...and therefore if the Player model modifies self, and the Card model modifies self.player in the same request, then the modifications won't take any notice of each other and the last-saved one will overwrite the others.
I'd like to work around this (presumably with some form of caching), so that all requests for a Player with a given id would return the same object (identical object_ids), thereby allowing both models to edit the same object without having to perform a database save-and-reload. I have three questions:
Is there already a plugin or gem to do this?
Are there good reasons why I shouldn't do this?
Can anyone give me some pointers on how to go about doing this?
This is supported in Rails 3.x. You can use the :inverse_of option for the has_many association for example. Documentation here (search for :inverse_of and Bi-directional associations).