: проблема отношения has_one при использовании MongoDB - PullRequest
1 голос
/ 21 января 2010

У меня довольно простая настройка. Подводя итог, вот что я делаю:

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'

Вот подвох: когда я заменяю отношение has_one ключом в модели Movie:

key :setting, Setting

... работает нормально. Нет ошибки стека.

Я мог бы просто отбросить отношение и перейти с ключом, но:

  • Это не красиво

  • Если я пытаюсь обновить movie.setting, используя .update_attributes, он удаляет все остальные атрибуты. Допустим, я обновляю movie.setting.key1, он сбрасывает movie.setting.key2 ... что нормально

Я не могу найти ничего полезного, поэтому любая помощь или указатели будут с благодарностью.

Ответы [ 2 ]

3 голосов
/ 21 января 2010

Я почти уверен, что отношения 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. См. Пример класса WindowSize в тестовом наборе MongoMapper.

0 голосов
/ 22 января 2010

В итоге я установил параметр в качестве ключа и перегрузил метод =:

в фильме

  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.

...