how to add records to has_many :through association in rails

Ruby on-RailsActiverecordHas Many-Through

Ruby on-Rails Problem Overview


class Agents << ActiveRecord::Base
  belongs_to :customer
  belongs_to :house
end

class Customer << ActiveRecord::Base
  has_many :agents
  has_many :houses, through: :agents
end

class House << ActiveRecord::Base
  has_many :agents
  has_many :customers, through: :agents
end

How do I add to the Agents model for Customer?

Is this the best way?

Customer.find(1).agents.create(customer_id: 1, house_id: 1)

The above works fine from the console however, I don't know how to achieve this in the actual application.

Imagine a form is filled for the customer that also takes house_id as input. Then do I do the following in my controller?

def create 
  @customer = Customer.new(params[:customer])
  @customer.agents.create(customer_id: @customer.id, house_id: params[:house_id])
  @customer.save
end

Overall I'm confused as to how to add records in the has_many :through table?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

I think you can simply do this:

 @cust = Customer.new(params[:customer])
 @cust.houses << House.find(params[:house_id])

Or when creating a new house for a customer:

 @cust = Customer.new(params[:customer])
 @cust.houses.create(params[:house])

You can also add via ids:

@cust.house_ids << House.find(params[:house_id])

Solution 2 - Ruby on-Rails

'The best way' depends on your needs and what feels most comfortable. Confusion comes from differences ActiveRecord's behavior of the new and create methods and the << operator.

The new Method

new will not add an association record for you. You have to build the House and Agent records yourself:

house = @cust.houses.new(params[:house])
house.save
agent = Agent(customer_id: @cust.id, house_id: house.id)
agent.save

Note that @cust.houses.new and House.new are effectively the same because you need to create the Agent record in both cases.

The << Operator

As Mischa mentions, you can also use the << operator on the collection. This will only build the Agent model for you, you must build the House model:

house = House.create(params[:house])
@cust.houses << house
agent = @cust.houses.find(house.id)
The create Method

create will build both House and Agent records for you, but you will need to find the Agent model if you intend to return that to your view or api:

house = @cust.houses.create(params[:house])
agent = @cust.agents.where(house: house.id).first

As a final note, if you want exceptions to be raised when creating house use the bang operators instead (e.g. new! and create!).

Solution 3 - Ruby on-Rails

Another way to add associations is by using the foreign key columns:

agent = Agent.new(...)
agent.house = House.find(...)
agent.customer = Customer.find(...)
agent.save

Or use the exact column names, passing the ID of the associated record instead of the record.

agent.house_id = house.id
agent.customer_id = customer.id

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMikeView Question on Stackoverflow
Solution 1 - Ruby on-RailsMischaView Answer on Stackoverflow
Solution 2 - Ruby on-RailsIAmNaNView Answer on Stackoverflow
Solution 3 - Ruby on-RailsDennisView Answer on Stackoverflow