Why is mongoid not allowing for the creation of a

2019-08-09 09:00发布

问题:

I am trying to add a new embedded document after deleting the embedded document. But I get an error when I use:

Code

u = User.last
u.classes.destroy_all
u.classes.create(:name => "Philsophy")
=> NoMethodError: undefined method `create' for []:Array

BUT, If I don't use a variable it WORKS. Can someone please explain this to me? I need to use the nested variable version to loop through a result set of hundreds of items.

User.last.classes.destroy_all
User.last.classes.create(:name => "Philsophy")
=> #<Class _id: philosophy, name: "Philosophy"> 

Ruby on Rails 3.0.3
Mongoid 2.0.0.beta.20 (Don't have a choice here)

Thanks

回答1:

I am not sure exactly what your models are here but I was only able to reproduce the error you are getting with something like this:

class User
  include Mongoid::Document

  embeds_many :classes
end

class Class
  include Mongoid::Document
  field :name

  embedded_in :user, :inverse_of => :classes
end

If that is what you have then the problem is that you are opening the Class class from the Ruby standard library and effectively extending it to be a Mongoid model. I guess that is not intentional. You have a couple of options in that case, you could just rename your Class class to something that isn't going to clash with the standard library, for example this works fine:

class User
  include Mongoid::Document

  embeds_many :courses
end

class Course
  include Mongoid::Document
  field :name

  embedded_in :user, :inverse_of => :courses
end

Or you could put your models in a namespace if you really want the call your class 'Class':

module Models
  class User
    include Mongoid::Document

    embeds_many :classes, :class_name => 'Models::Class'
  end

  class Class
    include Mongoid::Document
    field :name

    embedded_in :user, :inverse_of => :classes, :class_name => 'Models::User'
  end
end

If you do this then you will have to give Mongoid some help to find the target classes in each of your relations by specifying the class_name. So probably easiest to rename the class.

As to why the problem happens only when you use a variable like in your first example, I suspect it is because the destroy_all method leaves the classes collection in a broken state (a side-effect of the name clash). In your second example the second line is loading a fresh instance of the User model so that problem doesn't arise.