mongo_mapperのbelongs_toの参照が返すnilはnilじゃない
mongo_mapperを使い始める前に言っておくッ! おれは今やつのスタンドをほんのちょっぴりだが体験した い…いや…体験したというよりはまったく理解を超えていたのだが…… ,. -‐'''''""¨¨¨ヽ (.___,,,... -ァァフ| あ…ありのまま 今 起こった事を話すぜ! |i i| }! }} //| 『belongs_toを設定したモデルで、参照するドキュメントが |l、{ j} /,,ィ//| 設定されていないインスタンスを保存したんだが、 i|:!ヾ、_ノ/ u {:}//ヘ その参照をifで評価したら真と判断された』 |リ u' } ,ノ _,!V,ハ | /´fト、_{ル{,ィ'eラ , タ人 な… 何を言ってるのか わからねーと思うが /' ヾ|宀| {´,)⌒`/ |<ヽトiゝ おれも何をされたのかわからなかった… ,゙ / )ヽ iLレ u' | | ヾlトハ〉 |/_/ ハ !ニ⊇ '/:} V:::::ヽ 頭がどうにかなりそうだった… // 二二二7'T'' /u' __ /:::::::/`ヽ /'´r -―一ァ‐゙T´ '"´ /::::/-‐ \ keyやbelongs_toの記述ミスだとか / // 广¨´ /' /:::::/´ ̄`ヽ ⌒ヽ そんなチャチなもんじゃあ 断じてねえ ノ ' / ノ:::::`ー-、___/:::::// ヽ } _/`丶 /:::::::::::::::::::::::::: ̄`ー-{:::... イ もっと恐ろしいものの片鱗を味わったぜ…
mongo_mapperのバージョンは 0.7.6 だ
$ gem list -d mongo_mapper *** LOCAL GEMS *** mongo_mapper (0.7.6) Author: John Nunemaker Homepage: http://github.com/jnunemaker/mongomapper Installed at: /Users/takeshi/.rvm/gems/ruby-1.8.7-p249@mongo_mapper A Ruby Object Mapper for Mongo $ irb
irbで現象を確認する
require 'mongo_mapper' **Notice: C extension not loaded. This is required for optimum MongoDB Ruby driver performance. You can install the extension as follows: gem install bson_ext If you continue to receive this message after installing, make sure that the bson_ext gem is in your load path and that the bson_ext and mongo gems are of the same version. #=> true MongoMapper.database = "test01" #=> "test01" MongoMapper.connection = Mongo::Connection.new("localhost", 27017) #=> #<Mongo::Connection:0x10162bf40 @checked_out=[], @auths=[], @connection_mutex=#<Mutex:0x10162be28>, @logger=nil, @id_lock=#<Mutex:0x10162bea0>, @sockets=[], @timeout=5.0, @port=27017, @queue=#<ConditionVariable:0x10162bdd8>, @slave_ok=nil, @host="localhost", @nodes=[["localhost", 27017]], @safe_mutex=#<Mutex:0x10162be00>, @options={}, @size=1> class Bar include MongoMapper::Document key :name, String end #=> #<MongoMapper::Plugins::Keys::Key:0x1015a1368 @default_value=nil, @type=String, @name="name", @options={}> class Foo include MongoMapper::Document key :bar_id, ObjectId belongs_to :bar end #=> nil Foo.create #=> #<Foo _id: $oid4bfa44827693a1138e000001, bar_id: nil> Foo.all #=> [#<Foo _id: $oid4bfa44827693a1138e000001, bar_id: nil>] foo1 = Foo.first #=> #<Foo _id: $oid4bfa44827693a1138e000001, bar_id: nil> b1 = foo1.bar #=> nil
やってることは簡単だ。2つのドキュメントにマップされるクラスを作成して、FooがBarを参照できるように、Fooにはbar_idというキーを持ち、belongs_toを設定する。
そして、Fooのインスタンスに何も属性を指定せずにcreateしてドキュメントを保存し、その保存したものをfoo1として取得する。
この時のfoo1.barは何も指さない。nilを返すはずだ。そう表現されている。しかし。。。
b1 ? "T" : "F" #=> "T"
b1が真として評価されているッ!
条件演算子が信じられない人のためにif...else...endで書いておこう
if b1 puts "TRUE" else puts "FALSE" end TRUE #=> nil
やはりb1が真として評価されているッッッッッッ!
b1.nil?
#=> true
nil?に対してはtrueを返している・・・b1は何者なんだッッッ!?classを調べてやる
b1.class
#=> nil
おかしいぞッ!? nilのクラスはNilClassのはずッ!
nil.class #=> NilClass
もしや黒魔術では・・・?b1の特異クラスは・・・?
class << b1; self; end #=> #<Class:#<MongoMapper::Plugins::Associations::BelongsToProxy:0x10154b8a0>>
ビンゴ!!
b1.nil?
#=> true
という訳で、belongs_toで生成された参照先を取得するメソッドで、参照先が得られない場合の戻り値は、一見nilのように見えるがnilじゃない!!!
if、unless、条件演算子では期待通りに評価されないので、ARなどから移行する場合は気をつけろッ!!