Railsのhas_one / has_manyの:sourceオプションを理解する


184

関連付けの:sourceオプションを理解するのを手伝ってくださいhas_one/has_many :through。Rails APIの説明は、私にはほとんど意味がありません。

「指定で使用されるソース関連名has_many :through => :queries。名前は協会から推測することができない場合にのみ、それを使用するには。has_many :subscribers, :through => :subscriptionsどちらかを探します:subscribers:subscriberSubscriptionない限り、:source与えられています。」

回答:


238

場合によっては、関連付けごとに異なる名前を使用する必要があります。モデルの関連付けに使用する名前がモデルの関連付けと同じでない:through場合は、を使用:sourceして指定できます。

私は、上の段落があるとは思えないくらいので、ここでの例ですが、ドキュメント内の1つのより明確。との3つのモデルがPetあるDogとしDog::Breedます。

class Pet < ActiveRecord::Base
  has_many :dogs
end

class Dog < ActiveRecord::Base
  belongs_to :pet
  has_many :breeds
end

class Dog::Breed < ActiveRecord::Base
  belongs_to :dog
end

この例では、便利で便利な関連付けとしてDog::Breedアクセスするため、の名前空間を選択しましたDog.find(123).breeds

ここで、でhas_many :dog_breeds, :through => :dogs関連付けを作成したい場合Pet、突然問題が発生します。Railsはで:dog_breeds関連付けを見つけるDogことができないため、Railsはどの Dog関連付けを使用するか認識できません。入力してください:source

class Pet < ActiveRecord::Base
  has_many :dogs
  has_many :dog_breeds, :through => :dogs, :source => :breeds
end

では:source、Railsにモデルで呼び出さ:breedsれた関連付けDog探し(それがで使用されるモデルであるため:dogs)、それを使用します。


2
私はあなたがあなたの最後のクラスの動物をクラスペットと呼ぶことを意図していたと思います、私は信じているタイプミスです。
Kamilski81

3
上記の例では、下の関連べきDogBE has_many :breedの代わりに:breeds、次に:sourceである:breed代わりに、モデル名を表すように、単数形の:breedsテーブル名を表しますか?例has_many :dog_breeds, :through => :dogs, :source => :breeds接尾辞なし:breed)?
LazerSharks 2014

1
私はこれをテストしました。それは単数形で、s接尾辞はありません:source =>
Anwar

「この場合、Dog :: Breedに名前空間を付けることにしました。これは、Dog.find(123).breedsに便利で便利な関連付けとしてアクセスするためです。」名前空間は必要ありませんか?
Jwan622

201

その例を詳しく見てみましょう:

class User
  has_many :subscriptions
  has_many :newsletters, :through => :subscriptions
end

class Newsletter
  has_many :subscriptions
  has_many :users, :through => :subscriptions
end

class Subscription
  belongs_to :newsletter
  belongs_to :user
end

このコードを使用するNewsletter.find(id).usersと、ニュースレターの購読者のリストを取得するようなことができます。しかし、より明確にしてNewsletter.find(id).subscribers代わりに入力できるようにしたい場合は、Newsletterクラスを次のように変更する必要があります。

class Newsletter
  has_many :subscriptions
  has_many :subscribers, :through => :subscriptions, :source => :user
end

users関連付けの名前をに変更していsubscribersます。を指定しない場合:source、RailsはsubscriberSubscriptionクラスで呼び出された関連付けを探します。userサブスクライバーのリストを作成するには、サブスクリプションクラスの関連付けを使用するように指示する必要があります。


2
単数形のモデル名は:source =>、複数形ではなくで使用する必要があることに注意してください。だから、:users間違っている、:user正しいです
アンワル

これが最良の答えです!「ユーザーの関連付けの名前をサブスクライバーに変更しています。:sourceを指定しない場合、RailsはSubscriptionクラスでサブスクライバーと呼ばれる関連付けを探します。」
ブライアンジョセフスピノス2017年

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