Docs Menu
Docs Home
/ / /
Mongoid
/

継承

項目一覧

  • 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

上記の例では、 CanvasBrowserFirefoxはすべて clusters コレクションに保存されます。 データベースから読み込まれたときに正しいドキュメントが返されるようにするために、追加の属性_typeが保存されます。 これは、埋め込みドキュメントCircleRectangleShapeにも当てはまります。

注意

Circleを検索する場合、クエリはシェイプコレクション内のドキュメントのみを返します。 _type (または弁別子キーが設定されたもの)フィールドの値がCircle (または弁別子の値が設定されたもの) 、他のすべての弁別子の値は、Shape クラスのオブジェクトと見なされます。

同様に、親クラス(この例ではCanvas )でクエリを実行する場合、コレクション内のドキュメントのうち、弁別子値がないドキュメント、または弁別子値が親またはその子孫のいずれにもマップされていないものは、次として返されます。親クラスのインスタンス。

Mongoid は、弁別子キーのデフォルトの_typeからの変更をサポートしています。 これを行いたい場合がいくつかあります。

  1. 最適化: ユーザーは、 _tのような短いキーを使用したい場合があります。

  2. 既存のシステムを操作する場合: ユーザーは、事前に定義されたキーを持つ既存のシステムまたはデータセットを操作している可能性があります。

弁別子キーを変更するには、クラス レベルとグローバル レベルの 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" }

コレクションがサブクラスの一部に設定されており、他のサブクラスでは設定されていない場合、セット コレクションを持つサブクラスはそれらのコレクションにドキュメントを保存し、セット コレクションを持たないサブクラスは親の コレクションにドキュメントを保存します。

注意

サブクラスが保存されているコレクションを変更すると、そのサブクラスのドキュメントは、親クラスのクエリ結果に表示されなくなることに注意してください。

戻る

フィールドの定義