Railsで「has_many:through」リレーションを使用するのはいつですか?


123

私はそれが何でhas_many :through、いつそれを使用するのか(そしてその方法)を理解しようとしています。しかし、私はそれを得ていません。Beginning Rails 3を読んでいて、グーグルを試しましたが、理解できません。

回答:


177

2つのモデルがあるUserとしGroupます: と。

ユーザーをグループに所属させたい場合は、次のようにします。

class Group < ActiveRecord::Base
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :group
end

関連付けに関する追加のメタデータを追跡したい場合はどうなりますか?たとえば、ユーザーがグループに参加したとき、またはグループ内でのユーザーの役割は何か?

ここで、関連付けをファーストクラスオブジェクトにします。

class GroupMembership < ActiveRecord::Base
  belongs_to :user
  belongs_to :group

  # has attributes for date_joined and role
end

これにより、新しいテーブルが導入さgroup_idれ、ユーザーのテーブルから列が削除されます。

このコードの問題は、ユーザークラスを使用する他のすべての場所を更新して変更する必要があることです。

user.groups.first.name

# becomes

user.group_memberships.first.group.name

このタイプのコードは面倒で、このような変更を導入するのは面倒です。

has_many :through 両方の長所を提供します。

class User < ActiveRecord::Base
  has_many :groups, :through => :group_memberships  # Edit :needs to be plural same as the has_many relationship   
  has_many :group_memberships
end

これで通常のように扱うことができますがhas_many、必要なときに関連モデルのメリットを享受できます。

でこれを行うこともできますhas_one

編集:ユーザーをグループに簡単に追加できるようにする

def add_group(group, role = "member")
  self.group_associations.build(:group => group, :role => role)
end

2
これは、userモデルにメソッドを追加してグループを追加する場所です。先ほど行った編集のようなもの。お役に立てれば。
Ben Scheirman、2012

ええ、私も書く必要がありますuser.groups << groupか?それとも、すべてこの協会によって処理されますか?
LuckyLuke

group_membershipと同じクラスがありますが、factory girlを使用するときに問題が発生します。
Ayman Salah 2014年

「has_many:group_memberships」を使用します。単数形を使用しても機能しますが、user.group_membershipはコレクションになり、user.group_membershipsは機能しません。
calasyr、2015

それはタイプミスでした。修繕。
Ben Scheirman、2015

212

次のモデルがあるとします。

Car
Engine
Piston

has_one :engine
エンジンエンジンbelongs_to :car
エンジンhas_many :pistons
ピストンbelongs_to :engine

車のhas_many :pistons, through: :engine
ピストンhas_one :car, through: :engine

基本的に、あなたは他のモデルへのモデルの関係を委任されているので、代わりにコールを有するのcar.engine.pistonsは、あなただけ行うことができますcar.pistons


9
これはまったく理にかなっています!
RajG 2014年

24
これをSACA-ShortAndClearAnswerと呼びます。
Asmeが2014

18

ActiveRecord結合テーブル

has_many :throughまた、has_and_belongs_to_manyリレーションシップは、他のテーブル間のリレーションシップを表す中間テーブルである結合テーブルを通じて機能します。JOINクエリとは異なり、データは実際にはテーブルに格納されます。

実用的な違い

ではhas_and_belongs_to_many、主キーは必要なく、ActiveRecordモデルではなくActiveRecordリレーションを介してレコードにアクセスします。通常、多対多の関係で2つのモデルをリンクする場合は、HABTMを使用します。

has_many :through結合テーブルとRailsモデルとして対話する場合は、主キーと結合されたデータにカスタム列を追加する機能を備えた関係を使用します。後者は、結合された行に関連するデータでは特に重要ですが、実際には関連モデルには属していません。たとえば、結合された行のフィールドから派生した計算値を格納します。

こちらもご覧ください

ではActive Recordの組合に対するAガイド、勧告が読み取ります。

最も単純な経験則は、リレーションシップモデルを独立したエンティティとして使用する必要がある場合は、has_many:throughリレーションシップを設定する必要があるということです。リレーションシップモデルで何もする必要がない場合は、has_and_belongs_to_manyリレーションシップを設定する方が簡単な場合があります(ただし、データベースに結合テーブルを作成することを覚えておく必要があります)。

結合モデルで検証、コールバック、または追加の属性が必要な場合は、has_many:throughを使用する必要があります。

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