Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs Menu
Docs Home
/ /

関連付けの動作をカスタマイズする

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_keyforeign_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_keyinverse_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_many

  • embeds_one

  • has_many

  • has_one

  • has_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::BandTools::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_oneembeds_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。

戻る

埋め込み関連付け

項目一覧