has_manyにレコードを追加する方法:railsの関連付けを介して


94
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

どのようにAgentsモデルに追加しCustomerますか?

これは最善の方法ですか?

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

上記はコンソールからは問題なく動作しますが、実際のアプリケーションでこれを実現する方法はわかりません。

house_id入力としても使用されるフォームが顧客のために入力されていると想像してください。次に、コントローラで以下を実行しますか?

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

has_many :throughテーブルにレコードを追加する方法について全体的に混乱していますか?


どのコントローラに関数「create」を保存しますか?
Tobias Kolb 2018年

回答:


162

私はあなたがこれを簡単に行うことができると思います:

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

または、顧客のために新しい家を作成するとき:

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

ID経由で追加することもできます。

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

16
参考:親が既に保存されていない限り、関連する家を作成することはできません。
Ricardo Otero 2014

それは私が遭遇したこの問題に対する最もエレガントな解決策でなければなりません。+1してください。
Daniel Bonnell

私は、我々が使用することができますね@RicardoOtero buildのistead create
Karan

@Mischa House.find(params [:house_id])がnillの場合、エラーをどのように処理すればよいですか。params[:house_id]がnilの場合、TypeMismatchのエラーが発生します。すでにレスキューを使用しています。しかし、better_way .. ??
Vishal

1
<<演算子を使用すると、特定の場合に2回挿入されることがわかりました。したがって、このcreate方法が最良の方法です。
2017

77

「最善の方法」は、ニーズと最も快適に感じる方法によって異なります。混乱は、newおよびcreateメソッドと<<演算子のActiveRecordの動作の違いから生じます。

newメソッド

new関連付けレコードは追加されません。自分で作成しHouseAgent記録する必要があります。

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

両方のケースでレコードを作成する必要があるため、@cust.houses.newおよびHouse.newは事実上同じであることに注意してくださいAgent

<<オペレータ

Mischaが述べているよう<<に、コレクションに対して演算子を使用することもできます。これはAgentモデルを構築するだけなので、モデルを構築する必要がありますHouse

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

createメソッド

createは両方HouseAgentレコードを作成しますがAgent、ビューまたはapiにモデルを返す場合は、モデルを見つける必要があります。

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

最後に、作成時に例外を発生させたい場合houseは、代わりにbang演算子を使用します(例:new!およびcreate!)。


2
代わりに行をagent = @cust.houses.find(house.id)読む必要がありagent = @cust.agents.find(house.id)ますか?agent「新しいメソッド」の変数はagent、後者の例とは異なります。結合テーブルで追加の属性を操作する人々に混乱を招く可能性があります。
ヴォーン

特定の顧客のすべての家と対応するエージェントを表示するN + 1バグの例なしで、共同テーブルエージェントからのデータの取得について詳しく説明できますか
Ankita.P

6

関連付けを追加するもう1つの方法は、外部キー列を使用することです。

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

または、正確な列名を使用して、レコードの代わりに関連するレコードのIDを渡します。

agent.house_id = house.id
agent.customer_id = customer.id
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.