私はそれが何でhas_many :through
あり、いつそれを使用するか(そしてどのように)を理解しようとしています。しかし、私はそれを取得していません。Beginning Rails 3を読んでいて、グーグルを試しましたが、理解できません。
3 に答える
これらのモデルがあるとします。
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
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 :group_memberships
has_many :groups, :through => :group_memberships # Edit :needs to be plural same as the has_many relationship
end
これで、通常のように扱うことができますがhas_many
、必要なときにアソシエーションモデルのメリットを享受できます。
でこれを行うこともできることに注意してくださいhas_one
。
編集:ユーザーをグループに簡単に追加できるようにする
def add_group(group, role = "member")
self.group_associations.build(:group => group, :role => role)
end
ActiveRecord結合テーブル
has_many :through
リレーションシップは、他のテーブル間のリレーションシップを表す中間テーブルである結合テーブルhas_and_belongs_to_many
を介して機能します。JOINクエリとは異なり、データは実際にはテーブルに格納されます。
実用的な違い
を使用has_and_belongs_to_many
すると、主キーは不要であり、ActiveRecordモデルではなくActiveRecordリレーションを介してレコードにアクセスします。多対多の関係を持つ2つのモデルをリンクする場合は、通常、HABTMを使用します。
has_many :through
主キーと結合データにカスタム列を追加する機能を備えたRailsモデルとして結合テーブルを操作する場合は、リレーションシップを使用します。後者は、結合された行に関連するが、実際には関連するモデルに属していないデータにとって特に重要です。たとえば、結合された行のフィールドから導出された計算値を格納します。
関連項目
「アクティブレコードアソシエーションのガイド」の推奨事項は次のとおりです。
最も簡単な経験則は、関係モデルを独立したエンティティとして操作する必要がある場合は、has_many:through関係を設定する必要があるということです。リレーションシップモデルで何もする必要がない場合は、has_and_belongs_to_manyリレーションシップを設定する方が簡単な場合があります(ただし、データベースに結合テーブルを作成することを忘れないでください)。
結合モデルで検証、コールバック、または追加の属性が必要な場合は、has_many:throughを使用する必要があります。