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.
The above is how carrierwave-mongoid does it.
Thanks for reporting! Unfortunately I can't reproduce your issue, and I think it should work.
When I create a minimal example with:
everything works fine in rails console (using the default config from rails g mongoid:config):
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
1.9.3-p374 :003 > Post.new.respond_to? :decorate
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.
# => [B]
# => [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.
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:
If this is not the case, then please feel free to reopen this issue!
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?
I am using this with mongoid 3.0 btw.
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?
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!
Ok, thanks, good luck! I'd check that your engine doesn't explicitly require anything in app/models, which might be the problem.
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
is called, Mondoid::Document gets Draper::Decoratable included.
Due to (ruby#10248, ruby#9112) the models won't be "updated" to respond to decorate.