MongoDB
mongoid

mongoidでのfieldのdefault設定

More than 3 years have passed since last update.

概要

疑問

なぜfieldのdefaultの設定方法が2種類あるのか。

結論

defaultをlambdaで設定すると、その評価はオブジェクト作成時に評価される。

オブジェクト?インスタンスって言ったほうがいいのか?

公式ドキュメントを確認

http://mongoid.org/en/mongoid/docs/documents.html
上記ページのDefaultsの項にて

Defaults are either static values or lambdas.

とあって、要は普通に値を設定する方法とlambdaを使った方法の2種類がある。
で、なんで2種類?というのは

Be wary that default values that are not defined as lambdas or procs are evaluated at class load time, so the following 2 definitions are not equivalent. (You probably would prefer the second, which is at document creation time.)

とあるので、ざっと見lambdaやprocじゃない場合はクラスロード時に値が決定するよ、的なことが書いてあるし、その下の例もそんな意図で書いてある。

field :dob, type: Time, default: Time.now
field :dob, type: Time, default: ->{ Time.now }

検証

んじゃ試してみるか、と。

class Someting
  include Mongoid::Document

  field :time1, type: Time, default: Time.now
  field :time2, type: Time, default: ->{ Time.now }
end
pry(main)> Someting.new
=> #<Someting _id: 542eb1306b65796d25000000, time1: 2014-10-03 14:22:31 UTC, time2: 2014-10-03 14:22:40 UTC>
pry(main)> Someting.new
=> #<Someting _id: 542eb1386b65796d25010000, time1: 2014-10-03 14:22:31 UTC, time2: 2014-10-03 14:22:48 UTC>

timeの値はどっちも変わらないのだけど、time2の値は.newした時点の値になっていることが確認できた。

appendix

ちなみに既存のfieldに追加でdefaultを追加した場合や、新規でfield追加し、その後にSomething.firstとかで参照した場合の動作も同じっぽい。
lambdaの場合はSomething.firstするたびに時間がその時点の時間となったが、lambdaじゃない場合はクラスロード時の時間のままだった。

appendix2

Rubyに不慣れだった昔の自分向け

上記の検証はpryとかirbで試せる。
事前にgem install mongoidはしてある前提。

require 'mongoid'  # 追加箇所

class Someting
  include Mongoid::Document

  field :time1, type: Time, default: Time.now
  field :time2, type: Time, default: ->{ Time.now }
end

とすれば、その後はSomething.newとか。
でもDB接続はしていないのでSomething.createとかはエラーになる。