:使用MongoDB时has_one关系问题

时间:2010-01-21 17:17:16

标签: ruby-on-rails ruby stack mongodb mongomapper

我的设置非常简单。总结一下,这就是我正在做的事情:

class Movie
  include MongoMapper::Document
  has_one :setting
end

class Setting
  include MongoMapper::EmbeddedDocument
  belongs_to :movie
end

我想要做的是以与电影其他信息相同的形式更新电影的设置。因此,我这样做:

- form_for ['movies', @movie] do |f|
  # ...
  -f.fields_for @movie.setting do |ms|
    # ...

这不起作用,因为我收到此错误:

stack level too deep

[文字吼叫重复一百次左右]

/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/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'

以下是捕获:当我用Movie模型中的键替换has_one关系时:

key :setting, Setting

......它运作正常。没有堆栈错误。

我可以放弃关系并使用密钥但是:

  • 这不是很好

  • 如果我尝试使用.update_attributes更新movie.setting,则会删除所有其他属性。假设我更新了movie.setting.key1,它将重置movie.setting.key2 ...这是正常的

我找不到任何有用的东西,所以非常感谢任何帮助或指示。

2 个答案:

答案 0 :(得分:3)

我很确定嵌入式文档不支持has_one关系。因此,例如, 工作:

class Setting
  include MongoMapper::Document
  key :movie_id, ObjectId
  belongs_to :movie
end

class Movie
  include MongoMapper::Document
  one :setting, :class => Setting
end

如果您不想要您可能不需要的第一类设置文档,可以考虑使用Hash类型的键或您为Mongo定义的某个自定义类型的其他键来存储这些设置。有关示例,请参阅MongoMapper测试套件中的WindowSize类。

答案 1 :(得分:0)

我最终将设置设为键并重载=方法:

电影中的

  def setting=(new_setting)
    super ( (self.setting.nil?)? new_setting : (self.setting.keys.merge new_setting) )
  end

并在设置中

  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

这不是最优的,但是在有更好的方式进行has_one关系之前它会正常工作。