Mongoid Создать встроенный документ внутри родительского

У меня есть две модели User и Status. Статус встроен в пользователя:

User.rb

class User

  include Mongoid::Document
  include Mongoid::Timestamps

  embeds_one :status, as: :statusable

Status.rb

class Status

  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :statusable, polymorphic: true

Сейчас я пытаюсь создать статус Document Inside user:

* User.create!(:name =>'try',:status => {:num => '111'})
=> NameError: uninitialized constant Statu
    from /var/lib/gems/1.9.1/gems/activesupport-3.2.13/lib/active_support/inflector/methods.rb:230:in 'block in constantize'
    from /var/lib/gems/1.9.1/gems/activesupport-3.2.13/lib/active_support/inflector/methods.rb:229:in 'each'
    ....
    ....

* u = User.create!(:name =>'try')
u.status = Status.create!(:num => '222')
=> Mongoid::Errors::NoParent: 
Problem:
  Cannot persist embedded document Status without a parent document.
Summary:
  If the document is embedded, in order to be persisted it must always have a reference to its parent document. This is most likely caused by either calling Status.create or Status.create! without setting the parent document as an attribute.
Resolution:
  Ensure that you have set the parent relation if instantiating the embedded document direcly, or always create new embedded documents via the parent relation.

* u.status = {:num => '222'}
=> NameError: uninitialized constant Statu

Есть идеи, почему это происходит?

2 ответа

Решение

Из документации:

Название класса модели не может заканчиваться на "s", потому что оно будет рассматриваться как множественная форма слова. Например, Status будет рассматриваться как форма Statu во множественном числе, что вызовет несколько известных проблем.

Поэтому постарайтесь определить ваши отношения с class_name метаданные заставляют mongoid использовать этот класс.

embeds_one :status, as: :statusable, class_name: "Status"

Здесь было несколько проблем. Как ответил Маркес, имя класса модели, оканчивающееся на "s", проблематично, но адресуется через спецификатор class_name. Если вам не нужен полиморфизм, то вы просто используете автоматически сгенерированные методы для User # status и User # status =. Но с полиморфизмом и переопределением class_name спецификатор "as:" у меня не сработал, а сработал следующий. Надеюсь, что это поможет вам двигаться дальше.

приложение / модели / user.rb

class User
  include Mongoid::Document
  include Mongoid::Timestamps

  embeds_one :statusable, class_name: "Status"
end

приложение / модели / status.rb

class Status
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :statusable, polymorphic: true
end

Тест / блок / user_test.rb

require 'test_helper'
require 'pp'

class UserTest < ActiveSupport::TestCase
  def setup
    User.delete_all
  end

  test "basic embedding" do
    User.create!(:name =>'try',:statusable => {:num => '111'})
    assert_equal 1, User.count
    u = User.create!(:name =>'try')
    u.statusable = Status.new(:num => '222')
    assert_equal 2, User.count
    puts
    pp (User.all.to_a.collect{|user| user.serializable_hash})
  end
end

$ рейк тест

Run options:

# Running tests:

[1/1] UserTest#test_basic_embedding
[{"_id"=>"5277f5077f11bac4b4000001",
  "created_at"=>Mon, 04 Nov 2013 19:27:03 UTC +00:00,
  "name"=>"try",
  "statusable"=>
   {"_id"=>"5277f5077f11bac4b4000002",
    "created_at"=>nil,
    "num"=>"111",
    "updated_at"=>nil},
  "updated_at"=>Mon, 04 Nov 2013 19:27:03 UTC +00:00},
 {"_id"=>"5277f5077f11bac4b4000003",
  "created_at"=>Mon, 04 Nov 2013 19:27:03 UTC +00:00,
  "name"=>"try",
  "statusable"=>
   {"_id"=>"5277f5077f11bac4b4000004",
    "created_at"=>Mon, 04 Nov 2013 19:27:03 UTC +00:00,
    "num"=>"222",
    "updated_at"=>Mon, 04 Nov 2013 19:27:03 UTC +00:00},
  "updated_at"=>Mon, 04 Nov 2013 19:27:03 UTC +00:00}]
Finished tests in 0.044048s, 22.7025 tests/s, 45.4050 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
Другие вопросы по тегам