Does not work with mongoid #431

Closed
jpzwarte opened this Issue Jan 21, 2013 · 9 comments

Projects

None yet

3 participants

@jpzwarte
  def self.setup_orm(base)
    base.class_eval do
      include Draper::Decoratable
    end
  end

Afaict the above code does not work because Mongoid::Document is not a class but a module. If you run "Mongoid::Document.ancestors" in a rails console, you see only Mongoid::Document, even after running the above code in the console. Draper::Decoratable is also not listed in an actual class that includes Mongoid::Document. Running the above code against a model does give the desired result.

@jpzwarte
Mongoid::Document::ClassMethods.send(:include, CarrierWave::Mongoid)

The above is how carrierwave-mongoid does it.

@haines
Member
haines commented Jan 21, 2013

Thanks for reporting! Unfortunately I can't reproduce your issue, and I think it should work.

When I create a minimal example with:

# Gemfile
gem 'mongoid'
gem 'draper'

# app/models/post.rb
class Post
  include Mongoid::Document
end

everything works fine in rails console (using the default config from rails g mongoid:config):

1.9.3-p374 :001 > Post.ancestors
 => [Post, Mongoid::Document, Draper::Decoratable, ... ]
1.9.3-p374 :002 > Post.respond_to? :decorator_class
 => true 
1.9.3-p374 :003 > Post.new.respond_to? :decorate
 => true 

Can you try this? If this doesn't work for you, what Rails/Draper/Mongoid versions are you using?

Note that Mongoid::Document.ancestors does not include Draper::Decoratable because they are both ActiveSupport::Concerns, which uses append_features in a fairly clever way to allow one Concern to include another.

module A
  extend ActiveSupport::Concern
end

module B
  extend ActiveSupport::Concern
  include A
end

class C
  include B
end

B.ancestors
# => [B]

C.ancestors
# => [C, B, A, Object, Kernel, BasicObject]

CarrierWave does it that way because it only wants to add class methods (mount_uploader and so on from CarrierWave::Mount). However, we want to add both class and instance methods so that approach is not suitable.

@haines
Member
haines commented Jan 21, 2013

I have worked up some integration specs (#432) and this works for Mongoid 3.0+. I guess you are using Mongoid 2.x, which does not provide the load hook that we use in our railtie. You can add the following to an initializer:

# config/initializers/mongoid.rb
Draper.setup_orm Mongoid::Document

If this is not the case, then please feel free to reopen this issue!

@haines haines closed this Jan 21, 2013
@jpzwarte

Could this have something to do with timing? The mongoid models are from a dependent gem. I don't include draper until the gem is used in a rails application. So perhaps already existing models don't get the Decoratable concern mixed in?

@jpzwarte

I am using this with mongoid 3.0 btw.

@haines
Member
haines commented Jan 21, 2013

If the external gem loads its models before your Rails app starts, then they will include Mongoid::Document before it has received the include Decoratable, so yeah, in that case they wouldn't become decoratable.

However I don't think gems that add models should typically do this, though... in a Rails engine, the models get loaded after the initializers are run, so our hook would be activated and it would work fine. What is the external gem you are using? Is it not implemented as an engine?

@jpzwarte

Yep, i've implemented it as an engine. It's a private gem. I'll try and see if i can pinpoint the problem further. I'll update the issue when i have more info. Thanks for the quick response!

@haines
Member
haines commented Jan 21, 2013

Ok, thanks, good luck! I'd check that your engine doesn't explicitly require anything in app/models, which might be the problem.

@Zorbash
Zorbash commented Mar 17, 2015

We came across this issue a rails engine. In our case an initializer interacts with some of the mongoid models, causing autoloading and Mongoid::Document is included at that time. When

def self.setup_orm(base)
    base.class_eval do
      include Draper::Decoratable
    end
end

is called, Mondoid::Document gets Draper::Decoratable included.
Due to (ruby#10248, ruby#9112) the models won't be "updated" to respond to decorate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment