継承
Overview
Mongoid は、トップレベルと埋め込みドキュメントの両方での継承をサポートしています。 子ドキュメントが親ドキュメントから継承すると、親ドキュメントのフィールド、関連付け、検証、スコープが子ドキュメントにコピーされます。
class Canvas include Mongoid::Document field :name, type: String embeds_many :shapes end class Browser < Canvas field :version, type: Integer scope :recent, ->{ where(:version.gt => 3) } end class Firefox < Browser end class Shape include Mongoid::Document field :x, type: Integer field :y, type: Integer embedded_in :canvas end class Circle < Shape field :radius, type: Float end class Rectangle < Shape field :width, type: Float field :height, type: Float end
上記の例では、 Canvas
、 Browser
、 Firefox
はすべて clusters コレクションに保存されます。 データベースから読み込まれたときに正しいドキュメントが返されるようにするために、追加の属性_type
が保存されます。 これは、埋め込みドキュメントCircle
、 Rectangle
、 Shape
にも当てはまります。
注意
Circle
を検索する場合、クエリはシェイプコレクション内のドキュメントのみを返します。 _type
(または弁別子キーが設定されたもの)フィールドの値がCircle
(または弁別子の値が設定されたもの) 、他のすべての弁別子の値は、Shape クラスのオブジェクトと見なされます。
同様に、親クラス(この例ではCanvas
)でクエリを実行する場合、コレクション内のドキュメントのうち、弁別子値がないドキュメント、または弁別子値が親またはその子孫のいずれにもマップされていないものは、次として返されます。親クラスのインスタンス。
弁別子キーの変更
Mongoid は、弁別子キーのデフォルトの_type
からの変更をサポートしています。 これを行いたい場合がいくつかあります。
最適化: ユーザーは、
_t
のような短いキーを使用したい場合があります。既存のシステムを操作する場合: ユーザーは、事前に定義されたキーを持つ既存のシステムまたはデータセットを操作している可能性があります。
弁別子キーを変更するには、クラス レベルとグローバル レベルの 2 つの方法があります。 クラス レベルで弁別子キーを変更するには、ユーザーはdiscriminator_key=
メソッドを使用して親クラスに直接設定します。 上記の例で考えてみましょう。
class Shape include Mongoid::Document field :x, type: Integer field :y, type: Integer embedded_in :canvas self.discriminator_key = "shape_type" end class Circle < Shape field :radius, type: Float end class Rectangle < Shape field :width, type: Float field :height, type: Float end
ここで、 discriminator_key=
セッターへの呼び出しが親クラスに追加されました。 今後は、Rectal または円の作成時にshape_type
フィールドが追加されるようになっています。
弁別子キーは親クラスでのみ変更でき、子クラスでそれを設定しようとするとエラーが発生することに注意してください。
子クラスが作成された後に弁別子キーが変更された場合、新しい弁別子キー値を持つ新しいフィールドが追加され、古いフィールドは変更されません。 例:
class Shape include Mongoid::Document field :x, type: Integer field :y, type: Integer embedded_in :canvas end class Circle < Shape field :radius, type: Float end class Rectangle < Shape field :width, type: Float field :height, type: Float end Shape.discriminator_key = "shape_type"
この場合、Rectal または円の作成時に、shape_type
フィールドと_type
フィールドの両方が存在し、デフォルトはそれぞれRectangle
またはCircle
になります。
弁別子キーはグローバル レベルで設定することもできます。 つまり、すべてのクラスで、 _type
の代わりに、グローバルに設定された弁別子キーが使用されます。 上記の例で考えてみましょう。
Mongoid.discriminator_key = "_the_type" class Shape include Mongoid::Document field :x, type: Integer field :y, type: Integer embedded_in :canvas end class Circle < Shape field :radius, type: Float end class Rectangle < Shape field :width, type: Float field :height, type: Float end
グローバル弁別子キーを設定すると、すべてのクラスで弁別子キーとして_the_type
が使用され、 _type
フィールドが含まれなくなります。
グローバル レベルで弁別子キーを定義する場合、子クラスがそのグローバル値を使用するには、子クラスが定義される前にこのキーを設定する必要があることに注意してください。 ただし、グローバル レベルでは、子クラスを定義する前に弁別子キーを設定しない場合、弁別子フィールドはその子クラスの新しいグローバル設定ではなく、デフォルトの_type
を使用します。
弁別子の値の変更
Mongoid は、弁別子の値であるデフォルト値(クラス名)からの変更もサポートしています。 弁別子の値を変更するには、特定のクラスでdiscriminator_value=
メソッドを使用します。
上記の例で考えてみましょう。
class Shape include Mongoid::Document field :x, type: Integer field :y, type: Integer embedded_in :canvas end class Circle < Shape field :radius, type: Float self.discriminator_value = "round thing" end class Rectangle < Shape field :width, type: Float field :height, type: Float end
ここでは、 discriminator_value=
セッターへの呼び出しがCircle
に追加されました。 ここで、 Circle
の作成時に、ドキュメントにはキー_type
(またはdiscriminator_key
が変更されたもの)と値 "roundのように" を持つ フィールドが含まれます。
注意
弁別子の値のオーバーライドは子クラスで宣言されているため、クエリによって見つかる可能性のある子クラスは、そのクエリを送信する前にロードする必要があります。 上記の例では、返されたドキュメントがCircle
のインスタンスである可能性がある場合は、 Shape
でクエリを実行するときにCircle
クラス定義をロードする必要があります(オートロードでは"round thing"
がCircle
に解決されないため)。
サブクラスのクエリ
サブクラスのクエリは通常の方法で処理され、ドキュメントはすべて同じコレクション内にありますが、クエリは ActiveRecord の 単一テーブル継承 と同様に、正しいタイプのドキュメントのみを返します。
# Returns Canvas documents and subclasses Canvas.where(name: "Paper") # Returns only Firefox documents Firefox.where(name: "Window 1")
関連付け
関連付けが 1 つまたは複数ある に任意のタイプのサブクラスを追加するには、通常の設定または 関連付けのビルドと作成メソッドを使用します。
firefox = Firefox.new # Builds a Shape object firefox.shapes.build({ x: 0, y: 0 }) # Builds a Circle object firefox.shapes.build({ x: 0, y: 0 }, Circle) # Creates a Rectangle object firefox.shapes.create({ x: 0, y: 0 }, Rectangle) rect = Rectangle.new(width: 100, height: 200) firefox.shapes
永続性コンテキスト
Mongoid では、サブクラスの永続化コンテキストを、その親の永続化コンテキストから変更できます。 つまり、 store_in
メソッドを使用すると、サブクラスのドキュメントを親とは異なるコレクション(および異なるデータベース、クライアント)に保存できます。
class Shape include Mongoid::Document store_in collection: :shapes end class Circle < Shape store_in collection: :circles end class Square < Shape store_in collection: :squares end Shape.create! Circle.create! Square.create!
子に コレクションを設定すると、それらの子のドキュメントは親の コレクションではなく セット コレクションに保存されます。
> db.shapes.find() { "_id" : ObjectId("62fe9a493282a43d6b725e10"), "_type" : "Shape" } > db.circles.find() { "_id" : ObjectId("62fe9a493282a43d6b725e11"), "_type" : "Circle" } > db.squares.find() { "_id" : ObjectId("62fe9a493282a43d6b725e12"), "_type" : "Square" }
コレクションがサブクラスの一部に設定されており、他のサブクラスでは設定されていない場合、セット コレクションを持つサブクラスはそれらのコレクションにドキュメントを保存し、セット コレクションを持たないサブクラスは親の コレクションにドキュメントを保存します。
注意
サブクラスが保存されているコレクションを変更すると、そのサブクラスのドキュメントは、親クラスのクエリ結果に表示されなくなることに注意してください。