Question

I have two models User and Status. Status is embedded in User:

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

Now I'm trying to create the status 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

Any idea why this happens?

Was it helpful?

Solution

From documentation:

Model class name cannot end with "s", because it will be considered as the pluralized form of the word. For example Status would be considered as the plural form of Statu, which will cause a few known problems.

So try to define your relation with the class_name metadata forcing mongoid to use that Class.

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

OTHER TIPS

There were a couple of issues here. As answered by marquez, the model class name ending in "s" is problematic but addressable via the class_name specifier. If you didn't need polymorphism, then you would just use auto generated methods for User#status and User#status=. But with polymorphism and the class_name override, the "as:" specifier didn't work for me, but the following did. Hope that this helps you move on.

app/models/user.rb

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

  embeds_one :statusable, class_name: "Status"
end

app/models/status.rb

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

  embedded_in :statusable, polymorphic: true
end

test/unit/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

$ rake test

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top