フィールドの動作をカスタマイズする
項目一覧
Overview
このガイドでは、Mongoid モデルのフィールドの動作をカスタマイズする方法を学習できます。
デフォルト値の指定
default
オプションを使用して、フィールドをデフォルト値を持つように設定できます。 デフォルトのフィールド値は固定値または Proc
値のいずれかです。
次の例では、 state
フィールドに固定のデフォルト値を指定します。
class Order include Mongoid::Document field :state, type: String, default: 'created' end
次の例では、 fulfill_by
フィールドに Proc
のデフォルト値を指定します。
class Order include Mongoid::Document field :fulfill_by, type: Time, default: ->{ Time.now + 3.days } end
注意
ドライバーは、クラスが を読み込むと、Proc
インスタンスではないデフォルト値を評価します。ドライバーはドキュメントが インスタンス化される ときにProc
値を評価します。次のデフォルトのフィールド値では同等の結果は生成されません。
# Time.now is set to the time the class is loaded field :submitted_at, type: Time, default: Time.now # Time.now is set to the time the document is instantiated field :submitted_at, type: Time, default: ->{ Time.now }
Proc
インスタンスで self
キーワードを使用して、ドキュメントの状態に依存するデフォルト値を設定できます。 次の例では、 submitted_at
フィールドの状態に依存するように fulfill_by
のデフォルト値を設定します。
field :fulfill_by, type: Time, default: ->{ self.submitted_at + 4.hours }
デフォルトでは 、Mongoid は他のすべての属性を設定して初期化した後に、Proc
のデフォルト値を適用します。 他の属性を設定する前にデフォルトを適用するには、次の例に示すように、pre_processed
オプションを true
に設定します。
field :fulfill_by, type: Time, default: ->{ Time.now + 3.days }, pre_processed: true
Tip
_id
フィールドにデフォルトの Proc
値を設定するには、必ず pre-processed
オプションを true
に設定します。
ストレージ名の指定
アプリケーション内の元の名前でフィールドを参照しながら、データベースに保存する別のフィールド名を指定できます。 MongoDB はすべてのフィールド情報を各ドキュメントとともに保存するため、ストレージスペースを節約することができます。
as:
キーワードを使用して、代替ストレージ名を設定できます。 次の例では、 name
というフィールドを作成し、Mongoid が n
としてデータベースに保存します。
class Band include Mongoid::Document field :n, as: :name, type: String end
Mongoid は name
フィールドを"n"
として保存しますが、アプリケーションでは name
としてフィールドにアクセスできます。
フィールド エイリアス
alias_attribute
オプションを使用してフィールドのエイリアスを作成できます。 エイリアスを指定しても、Mongoid がデータベースにフィールドを保存する方法は変更されませんが、アプリケーション内の別の名前でフィールドにアクセスできるようになります。
次の例では、 name
フィールドのエイリアスを指定します。
class Band include Mongoid::Document field :name, type: String alias_attribute :n, :name end
フィールドエイリアスを削除するには、unalias_attribute
オプションを使用できます。 次の例では、 name
フィールドの エイリアスを削除します。
class Band unalias_attribute :n end
また、unalias_attribute
を使用して、事前定義された id
エイリアスを _id
フィールドから削除することもできます。 これを使用して、 _id
フィールドと id
フィールドに異なる値を保存できます。
フィールドの再定義
デフォルトでは 、Mongoid ではモデルのフィールドを再定義できます。 フィールドが再定義されたときにエラーを発生させるには、mongoid.yml
ファイルの duplicate_fields_exception
構成オプションを true
に設定します。
duplicate_fields_exception
オプションが true
に設定されている場合でも、フィールド を定義するときに overwrite
オプションを true
に設定することで、特定のフィールドを再定義できます。 次の例ではname
フィールドを定義し、overwrite
オプションを使用してそのフィールドを再定義します。
class Person include Mongoid::Document field :name field :name, type: String, overwrite: true end
カスタムIDフィールド
デフォルトでは 、Mongoid はドキュメントの _id
フィールドを定義し、Mongoid が自動的に生成する BSON::ObjectId
値を含めます。 モデルで指定することで、_id
フィールドのタイプをカスタマイズしたり、デフォルト値を指定したりできます。
次の例では、カスタム _id
フィールドを持つ Band
クラスを作成します。
class Band include Mongoid::Document field :name, type: String field :_id, type: String, default: ->{ name } end
_id
フィールドのデフォルト値を省略できます。 フィールドにデフォルト値を指定しない場合、Mongoid は _id
値なしでドキュメントを永続化します。 最上位ドキュメントの場合、 MongoDBサーバーは自動的に _id
値を割り当てます。 ただし、埋め込みドキュメントの場合、サーバーは_id
値を割り当てません。
_id
フィールドの値を指定しない場合、Mongoid はサーバーから自動的に割り当てられた値を取得しません。 このため、_id
値を使用してデータベースからドキュメントを取得することはできません。
キャストできない値
指定されたフィールド型に変換できない値は、キャスト不可と見なされます。例、配列は Integer
フィールドに割り当てられている場合、キャスト不可と見なされます。
v8.0 以降では、Mongoid は nil
をキャスト不可の値に割り当てます。 元のキャストできない値は、フィールド名とともに attributes_before_type_cast
ハッシュに保存されます。
カスタム ゲッターとセッター
フィールドと同じ名前のメソッドを指定し、read_attribute
メソッドまたは write_attribute
メソッドを呼び出して未加工の属性値で操作することで、フィールドのデフォルトの getter メソッドと setter メソッドを上書きできます。
次の例では、 Person
クラスの name
フィールドのカスタム getter と setter を作成します。
class Person include Mongoid::Document field :name, type: String # Custom getter for 'name' to return the name in uppercase def name read_attribute(:name).upcase if read_attribute(:name) end # Custom setter for 'name' to store the name in lowercase def name=(value) write_attribute(:name, value.downcase) end end
読み取り専用属性
attr_readonly
オプションを指定することで、読み取り専用のフィールドを指定できます。 これにより、 属性を持つドキュメントを作成できますが、更新はできません。
次の例では、 Band
クラスを作成し、name
フィールドを読み取り専用として指定しています。
class Band include Mongoid::Document field :name, type: String field :origin, type: String attr_readonly :name end
一括更新メソッド(update_attributes
など)を呼び出し、読み取り専用フィールドを渡すと、Mongoid は読み取り専用フィールドを無視し、他のすべてを更新します。 読み取り専用フィールド を明示的に更新しようとすると、Mongoid は ReadonlyAttribute
例外を発生させます。
注意
bit
や inc
などのアトミック永続演算子を呼び出しても、読み取り専用フィールドへの変更は保持されます。
モデル全体を読み取り専用として指定する方法については、「 データ操作の実行 」ガイドの「 読み取り専用ドキュメント セクション」を参照してください。
フィールドのローカル化
Mongoid は、 i18 n gem を使用してローカライズされたフィールドをサポートしています。フィールドをローカル化すると、Mongoid はそのフィールドをロケールキーと値のハッシュとして保存します。 フィールドへのアクセスは、string 値と同じように動作します。 任意のフィールドタイプのフィールドをローカライズできます。
次の例では、ローカライズされた review
フィールドを持つ Product
クラスを作成します。
class Product include Mongoid::Document field :review, type: String, localize: true end I18n.default_locale = :en product = Product.new product.review = "Marvelous!" I18n.locale = :de product.review = "Fantastisch!" product.attributes # Outputs: { "review" => { "en" => "Marvelous!", "de" => "Fantastisch!" }
_translations
メソッドを呼び出すと、一度にすべての翻訳を取得して設定できます。
product.review_translations # Outputs: { "en" => "Marvelous!", "de" => "Fantastisch!" } product.review_translations = { "en" => "Marvelous!", "de" => "Wunderbar!" }
i18 フォールバック機能を有効にすることで、ローカライズされたフィールドのフォールバックを指定できます。
Railsアプリケーションでフォールバックを有効にするには、環境で config.i18n.fallbacks
構成設定を設定し、フォールバック言語を設定します。
config.i18n.fallbacks = true config.after_initialize do I18n.fallbacks[:de] = [ :en, :es ] end
モジュールを i18nバックエンドに含め、フォールバック言語を設定することで、非 Rails アプリケーションでフォールバックを有効にします。
require "i18n/backend/fallbacks" I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) I18n.fallbacks[:de] = [ :en, :es ]
フォールバック を有効にした後、アクティブな言語に翻訳がない場合は、指定された フォールバック言語で検索されます。
フィールド を定義するときに fallbacks
オプションを false に設定することで、指定されたフィールドのフォールバック言語を無効にすることができます。
class Product include Mongoid::Document field :review, type: String, localize: true, fallbacks: false end
ローカライズされたフィールドをクエリする場合、Mongoid は現在のロケールと一致するようにクエリ条件を自動的に変更します。 次の例では、 en
ロケールでレビューを得るために Product
クラスをクエリします。
# Match all products with Marvelous as the review. The current locale is :en. Product.where(review: "Marvelous!") # The resulting MongoDB query filter: { "review.en" : "Marvelous!" }
注意
ローカライズされたフィールドを広範にクエリする場合は、クエリを実行するロケールごとにインデックスを作成することをお勧めします。