1

I have class & subclass with one document looks like :

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

  store_in collection: 'users'
end

class Core::Moderator < Core::User

end

I tried to add a user from console

2.4.2 :002 >  user = Core::User.new(email: 'email@domain.com', name: 'new user')
 => #<Core::User _id: BSON::ObjectId('5a015465fe37a86430b1e0ff'), created_at: nil, email: "email@domain.com", name: "new_user", updated_at: nil> 
2.4.2 :003 > user.save
 => true 
2.4.2 :004 > user._type
NoMethodError: undefined method `_type' for #<Core::User:0x0000000003e77ea0>
    from (irb):4

And then add new moderator :

2.4.2 :005 > moderator = Core::Moderator.new(email: 'email2@domail.com', name: 'new moderator')
#<Core::Moderator _id: BSON::ObjectId('5a015600fe37a86430b1e100'), created_at: nil, email: "email2@domain.com", name: "new moderator", updated_at: nil>
2.4.2 :006 > moderator.save
=> true 
2.4.2 :007 > moderator._type
=> "Core::Moderator"

Next add new user again :

2.4.2 :008 >  user = Core::User.new(email: 'email3@domain.com', name: 'new user 2')
 => #<Core::User _id: BSON::ObjectId('5a015704fe37a86430b1e101'), created_at: nil, email: "email3@domain.com", name: "new user 2", updated_at: nil> 
2.4.2 :009 > user.save
 => true 
2.4.2 :010 > user._type
 => "Core::User"

Why I should create subclass first to get field _type on parent class? Every I start new console and create new user (Core::User) the field _type not generated.

I user Ruby 2.4.2, Rails 5.1.4, Mongoid 6.2.1

itx
  • 1,327
  • 1
  • 15
  • 38
  • I guess not using `Core::Moderator` first lead to the situation that Rails doesn't know that `Core::User` has subclasses and therefore doesn't load the STI helper methods. What happens if you load the subclass `Core::Moderator` first without building an instance and then build an `Core::User`. – spickermann Nov 07 '17 at 07:05
  • @spickermann when load subclass `Core::Moderator` first, and build `Core::User`, the field `_type` created. FYI I have another apps but using rails 4.x.x with same model structure, I shouldn't load subclass first, the field `_type` generate when build a class. – itx Nov 07 '17 at 07:32
  • I would be too surprised if the internals of Rails' autoloading and preloading implementation have changed between 4.x and 5.1 But I would be surprised if Rails knew that a class has subclasses without loading at least one of them. – spickermann Nov 07 '17 at 08:09
  • @spickermann I found it. If i set `true` for `eager_load`, rails knew a class has subclasses. https://stackoverflow.com/q/19839847/1297435 – itx Nov 07 '17 at 10:30
  • @spickermann "Rails' autoloading and preloading implementation have changed between 4.x and 5.1" - that's ActiveRecord. This is a Mongoid question which uses a completely different codebase. – max Nov 07 '17 at 12:45
  • 1
    @max The OP uses Mongoid in a Rails application. This and the fact that enabling Rails' `eager_load` fixes the issue make me confident that it is a Rails autoload problem and not a Problem cause by Mongoid. – spickermann Nov 07 '17 at 14:10
  • Sorry you're completely right @spickermann. I was thinking of `ActiveRecord::Relation.preload` not class reloading. – max Nov 07 '17 at 14:12
  • But I was kind of right @spickermann since mongoid has its own eager loading mechanism and config option for models. – max Nov 07 '17 at 15:46

1 Answers1

1

In order for inheritance to work as expected in Mongoid you need to set preload_models: true. Otherwise the model cannot know that it has subclasses.

# config/mongoid.yml
development:
  # ...
  options: 
    # ...
    # Preload all models in development, needed when models use
    # inheritance. (default: false)
    preload_models: true 
max
  • 96,212
  • 14
  • 104
  • 165
  • I think I need mongoid read documentation again, I usually using activerecord... thanks @max .. here is for documentation about `preload_models` https://docs.mongodb.com/mongoid/master/tutorials/mongoid-rails/#model-preloading – itx Nov 08 '17 at 01:37