:has_one relationship problem when using MongoDB
I have a pretty simple setup. To sum it up here's what I'm doing:
class Movie
include MongoMapper::Document
has_one :setting
end
class Setting
include MongoMapper::EmbeddedDocument
belongs_to :movie
end
What I want to do is to update the setting of a movie in the same form as the movie other information. Therefor I do that :
- form_for ['movies', @movie] do |f|
# ...
-f.fields_for @movie.setting do |ms|
# ...
This doesn't work as I get this error :
stack level too deep
[text bellow is repeated a hundred time or so]
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/one_proxy.rb:46:in开发者_StackOverflow `find_target'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/proxy.rb:98:in `load_target'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/proxy.rb:88:in `method_missing'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/one_proxy.rb:56:in `target_class'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/one_proxy.rb:46:in `find_target'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/proxy.rb:98:in `load_target'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations/one_proxy.rb:17:in `replace'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/associations.rb:39:in `setting='
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/embedded_document.rb:185:in `send'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/embedded_document.rb:185:in `initialize'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/embedded_document.rb:177:in `each'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/embedded_document.rb:177:in `initialize'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/dirty.rb:42:in `initialize'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/embedded_document.rb:91:in `new'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/embedded_document.rb:91:in `initialize_doc'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/document.rb:316:in `find_one'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/document.rb:321:in `find_one!'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/document.rb:88:in `find!'
/Users/marc/.gem/ruby/1.8/gems/mongo_mapper-0.6.10/lib/mongo_mapper/document.rb:96:in `find'
/Users/marc/Code/mycompany/dontreadthat/sources/app/controllers/application_controller.rb:53:in `set_page_title'
Here's the catch : When I replace the has_one relationship by a key in the Movie model:
key :setting, Setting
... it works fine. No stack error.
I could just drop the relation and go with the key but :
It's not pretty
If I try to update movie.setting using .update_attributes it drops all the other attributes. Let's say I update movie.setting.key1, it will reset movie.setting.key2... which is normal
I can't find anything helpful out there, so any help or pointers would be greatly appreciated.
I'm pretty sure that has_one relationships aren't supported as embedded documents. So, for example, this does work:
class Setting
include MongoMapper::Document
key :movie_id, ObjectId
belongs_to :movie
end
class Movie
include MongoMapper::Document
one :setting, :class => Setting
end
If you don't want the first-class Settings document, which you probably don't need, you might consider storing these settings using a key of type Hash or another key of some custom type you've defined for Mongo. See the WindowSize class in the MongoMapper test suite for an example.
I ended up setting the Setting as a key and overloading the = method :
in movie
def setting=(new_setting)
super ( (self.setting.nil?)? new_setting : (self.setting.keys.merge new_setting) )
end
and in setting
def keys
keys_hash = {}
self.attributes.each do |attribute|
keys_hash.merge!( {attribute[0].to_s => attribute[1].to_s}) unless attribute[0].to_s == "_id"
end
return keys_hash
end
It's not optimal, but it'll work fine until there is a better way of doing has_one relationships.
精彩评论