Overview
Mongoid の関連付けにより、モデル間の関係を作成できます。このガイドでは、Mongoid を使用して、アプリケーション内で関連付けの動作をカスタマイズする方法を学習できます。次のセクションでは、関連付けの動作をカスタマイズする方法について説明します。
拡張機能
拡張機能を使用すると、関連付けにカスタム機能を追加できます。 次の例に示すように、関連付け定義で ブロックを指定することで、関連付けで拡張機能を定義できます。
class Band include Mongoid::Document embeds_many :albums do def find_by_name(name) where(name: name).first end end end band.albums.find_by_name("Omega") # returns album "Omega"
カスタム関連付け名
class_name マニュアルを使用して、関連付けのカスタムクラス名を指定できます。これは、クラスの名前とは異なるものに関連付けに名前を付けたい場合に便利です。次の例では、class_name マイクロを使用して、records という埋め込み関連付けが Albumクラスを表すことを指定します。
class Band include Mongoid::Document embeds_many :records, class_name: "Album" end
カスタムキー
デフォルトでは 、Mongoid は関連付けを検索するときに親クラスの _idフィールドを使用します。 primary_key と foreign_key マイクロを使用して、使用する別のフィールドを指定できます。 次の例ではBandクラスの albums 関連付けの新しいプライマリキーと外部キーを指定します。
class Band include Mongoid::Document field :band_id, type: String has_many :albums, primary_key: 'band_id', foreign_key: 'band_id_ref' end class Album include Mongoid::Document field :band_id_ref, type: String belongs_to :band, primary_key: 'band_id', foreign_key: 'band_id_ref' end
has_and_belongs_to_many の関連付けを指定している場合は、inverse_primary_key と inverse_foreign_key マイクロも使用できます。 inverse_primary_key マニュアルは、リモート モデルがドキュメントを検索するために使用するローカル モデルのフィールドを指定します。 inverse_foreign_key マイクロは、inverse_primary_key で見つかった値を保存するリモート モデルのフィールドを指定します。
次の例では、 has_and_belongs_to_many の関連付けにおいて Band クラスと Members クラスの新しいプライマリキーと外部キーを指定します。
class Band include Mongoid::Document field :band_id, type: String field :member_ids, type: Array has_many :members, primary_key: 'member_id', foreign_key: 'member_ids', inverse_primary_key: 'band_id', inverse_foreign_key: 'band_ids' end class Member include Mongoid::Document field :member_id, type: String field :band_ids, type: Array has_many :bands, primary_key: 'band_id', foreign_key: 'band_ids', inverse_primary_key: 'member_id', inverse_foreign_key: 'member_ids' end
カスタムスコープ
scope パラメータを使用して、関連付けの範囲を指定できます。 scope パラメーターは、Mongoid が関連付けの一部と見なすドキュメントを決定します。 スコープ指定された関連付けでは、クエリ時にスコープ条件に一致するドキュメントのみが返されます。 scope は、アーティッドがゼロの Proc または、関連付けられたモデル上の名前付きスコープを参照する Symbol に設定できます。 次の例では、 Bandクラスでの関連付けにカスタム スコープを設定します。
class Band include Mongoid::Document has_many :albums, scope: -> { where(published: true) } # Uses a scope called "upcoming" on the Tour model has_many :tours, scope: :upcoming end
注意
スコープ条件に一致しないドキュメントを 関連付けに追加できます。 Mongoid はドキュメントをデータベースに保存し、関連するメモリに表示されます。 ただし、関連付けをクエリするときに、ドキュメントは表示されません。
検証
Mongoid が関連付けをメモリに読み込むとき(デフォルトでは )、validates_associated マイクロを使用して子も存在することを検証します。 Mongoid は、次の関連付けタイプの子を検証します。
embeds_manyembeds_onehas_manyhas_onehas_and_belongs_to_many
この検証動作をオフにするには、次の例に示すように、関連付けを定義するときに validate マイクロを false に設定します。
class Band include Mongoid::Document embeds_many :albums, validate: false end
多形
Mongoid は、子クラスの 1 対 1 および 1 対多の関連付けの多形データをサポートします。 多形関連付けにより、1 つの関連付けに異なるクラスタイプのオブジェクトを含めることができます。 子関連付けで polymorphic オプションを true に設定し、親関連付けに as オプションを追加することで、多態的な 関連付けを定義できます。 次の例では、 Bandクラスで多態的な 関連付けを作成しています。
class Tour include Mongoid::Document has_one :band, as: :featured end class Label include Mongoid::Document has_one :band, as: :featured end class Band include Mongoid::Document belongs_to :featured, polymorphic: true end
前の例では、Bandクラスの :featured の関連付けに Label または Album のドキュメントのいずれかを含めることができます。
重要
Mongoid は、子から親への多形データのみをサポートします。 親の has_one または has_many の関連付けを多形として指定することはできません。
has_and_belongs_to_many 関連付けは多形データをサポートしていません。
カスタム多形タイプ
バージョン 9.0.2 以降、 Mongoid は、グローバル レジストリを通じてカスタム多形型をサポートします。 別のキーを指定して異なるクラスを表すことができ、コードを データから切り離します。 次の例ではBandクラスの代替キーとして string "artist" を指定します。
class Band include Mongoid::Document identify_as 'artist' has_many :albums, as: :record end
前の例では、identify_as ディレクティブは Mongoid に指示して、データベースにBand クラスをstring"artist" として保存します。
次の例に示すように、複数のエイリアスを指定することもできます。
class Band include Mongoid::Document identify_as 'artist', 'group', 'troupe' has_many :albums, as: :record end
前の例では、artist はデフォルト名で、その他はレコードを検索する目的でのみ使用されています。 これにより、データの 関連付けを中断せずにコードをリファクタリングできます。
多形型エイリアスはグローバルです。 指定するキーは、コード ベース全体で一意である必要があります。 ただし、モデルのさまざまなサブセットに使用できる代替のリゾルバを登録することはできます。 この場合、キーは各リゾルバに対してのみ一意である必要があります。 次の例は、代替リゾルバを登録する方法を示しています。
Mongoid::ModelResolver.register_resolver Mongoid::ModelResolver.new, :mus Mongoid::ModelResolver.register_resolver Mongoid::ModelResolver.new, :tool module Music class Band include Mongoid::Document identify_as 'bnd', resolver: :mus end end module Tools class Band include Mongoid::Document identify_as 'bnd', resolver: :tool end end
Music::Band と Tools::Band は両方とも "bnd" のエイリアスですが、各モデルは競合を回避するために独自のリゾルバを使用します。
依存関係の動作
参照された関連付けに dependent オプションを指定すると、ドキュメントが削除されたときに Mongoid が関連するドキュメントをどのように取り扱うかを指定できます。 次のオプションを指定できます。
delete_all: モデル コールバックを実行中せずにすべての子ドキュメントを削除します。destroy: 子ドキュメントを削除し、すべてのモデル コールバックを実行します。nullify: 子ドキュメントの外部キーをnilに設定します。 親ドキュメントのみが参照する場合、子ドキュメントが 孤立する 可能性があります。restrict_with_exception: 子ドキュメントが空でない場合に例外が発生します。restrict_with_error: 子ドキュメントが空でない場合は、操作をキャンセルし、falseを返します。
dependent オプションを指定しない場合、親ドキュメントが削除されても Mongoid は子ドキュメントを変更せずに残ります。 子ドキュメントは削除された親ドキュメントを参照、親のみを介して参照されると、子ドキュメントは孤立します。
次の例ではBandクラスで dependent オプションを指定します。
class Band include Mongoid::Document has_many :albums, dependent: :delete_all belongs_to :label, dependent: :nullify end
参照された関連付けの自動保存
デフォルトでは 、Mongoid は親ドキュメント を保存するときに、非埋め込み関連付けから関連するドキュメントを自動的に保存しません。 これにより、存在しないドキュメントへの参照が切断される可能性があります。
参照された関連付けで autosave オプションを使用すると、親ドキュメント を保存するときに関連するドキュメントを自動的に保存できます。 次の例では、関連付けられた Albumクラスを持つ Bandクラスを作成し、autosave オプションを指定しています。
class Band include Mongoid::Document has_many :albums end class Album include Mongoid::Document belongs_to :band, autosave: true end band = Band.new album = Album.create!(band: band) # The band is persisted at this point.
注意
Mongoid は、accepts_nested_attributes_for オプションを使用する関連付けにオート保存機能を自動的に追加します。
Mongoid は親ドキュメントに埋め込みドキュメントを保存するため、埋め込み関連付けに autosave オプションを指定する必要はありません。
自動構築
has_one や embeds_one などの 1 対 1 の関連付けに autobuild オプションを追加すると、nil 関連付けにアクセスするときに新しいドキュメントを自動的にインスタンス化できます。 次の例では、 Bandクラスの関連付けに autobuild オプションを追加します。
class Band include Mongoid::Document embeds_one :label, autobuild: true has_one :producer, autobuild: true end
タップ
Mongoid がドキュメントに入力すると、ドキュメントのupdated_at フィールドが現在の日付と時刻に更新されます。任意の belongs_to 関連付けに touch オプションを追加すると、子ドキュメントが更新されるたびに Mongoid が親ドキュメントにアクセスするようになります。 次の例では、 Bandクラスの関連付けに touch オプションを追加します。
class Band include Mongoid::Document field :name belongs_to :label, touch: true end
touch オプションを使用して、親関連付けの別のフィールドをstring またはシンボルとして指定することもできます。 Mongoid が親関連付けにアクセスすると、updated_atフィールドと指定されたフィールドの両方が現在の日付と時刻に設定されます。
次の例ではMongoid に bands_updated_atフィールドにアクセスするように指示します。
class Band include Mongoid::Document belongs_to :label, touch: :bands_updated_at end
注意
埋め込み関連付けでは、埋め込みドキュメントが操作されると、Mongoid はその親を再帰的に操作します。 このため、embedded_in の関連付けに touch 属性を追加することは不要です。
Mongoid は、embedded_in 関連付けでアクセスする追加フィールドの指定をサポートしていません。
カウンター キャッシュ
関連付けられたフィールドに属するオブジェクトの数を保存するには、counter_cache オプションを使用します。このオプションを指定すると、Mongoid は関連付けられた親モデルにカウンターフィールドを保存します。
counter_cache オプションは、カウンターフィールド名として次の 2 つの値のいずれかを受け入れます。
true: Mongoid は、関連付けの名前に基づいて、デフォルトのカウンターフィールド名を使用します。例、関連付けがBandと呼ばれている場合、デフォルトのカウンターフィールド名はbands_countです。stringまたはsymbol: Mongoid は、その値をカウンターフィールド名として直接使用します。
次のいずれかの方法で、カウンターキャッシュのコンテナを提供できます。
親モデルで明示的なカウンターフィールドを定義します。
親モデルに
Mongoid::Attributes::Dynamicモジュールを含めます。これにより、Mongoid は最初の使用時に は、カウンターフィールドを動的に作成できます。
明示的なカウンターフィールド
このアプローチでは、親モデルでカウンターフィールドを直接宣言します。これは、固定のスキーマと明示的なフィールドタイプが必要な場合に便利です。
次の例では、Labelクラスで明示的な bands_countフィールドを宣言し、デフォルトのカウンターフィールド名を使用しています。
class Band include Mongoid::Document # Uses the default counter field name: bands_count belongs_to :label, counter_cache: true end class Label include Mongoid::Document field :bands_count, type: Integer has_many :bands end
counter_cache オプションに string を渡して、カスタム カウンターフィールド名を指定することもできます。
class Band include Mongoid::Document belongs_to :label, counter_cache: :active_bands_count end class Label include Mongoid::Document field :active_bands_count, type: Integer has_many :bands end
動的カウンター フィールド
親モデルに Mongoid::Attributes::Dynamic モジュールを含めると、Mongoid は実行中に カウンターフィールドを動的に作成および更新できます。これは、柔軟なスキーマが必要で、カウンターフィールドを明示的に宣言したくない場合に便利です。
次の例では、Mongoid::Attributes::Dynamic を使用して、Mongoid が Labelクラスに カウンターフィールドを動的に作成できるようにします。
class Band include Mongoid::Document belongs_to:label, counter_cache: true end class Label include Mongoid::Document include Mongoid::Attributes::Dynamic has_many :bands end
Mongoid::Attributes::Dynamic モジュールを使用すると、Mongoid は 明示的なカウンターフィールドを宣言する場合と同じ命名ルールをカウンターフィールドに使用します。でカスタムフィールド名を指定しない限り、関連付けに基づいて *_countフィールド名がデフォルトになります。 counter_cache オプションの string。