Reputation: 11368
I am developing Rails plugin (it is 3.1 Engine) called Carrier (https://github.com/stanislaw/carrier).
In one of my rails app I want to extend Carrier's controller with some new methods - fx. add new action #comment_form to Carrier::MessagesController (I want this action only exist in my app - I don't want to add it in Engine - because it is very specific).
Two strategies I see here:
1) I copy {Carrier's plugin root}/app/controllers/carrier/messages_controller.rb file to app/controllers/carrier/ folder of my app, and then extend it (all plugin's original actions are copied to rails app controllers folder too!).
2) More accurate way I want - is just to create {My rails app}/app/controllers/carrier/messages_controller.rb and write only #comment_form method I want Carrier to be extended with.
Expecting that two controllers's content (original from plugin's folder + custom in my rails app having only new #comment_form) will superpose, I tried the second way. But Rails then stopped recognizing all original Carrier's actions (#index, #show, etc...) written in messages_controller.rb from the Carrier plugin's folder and began treating rails app's messages_controller.rb version as the only one (all original actions began treated as empty and thus began rendered through rails conventions default flow).
So my question in general is: How to add new actions to Rails Engines controllers without copying them entirely to Rails app/controllers folder?
UPD
For now I see two solutions which allow extension of engine's controllers without serious hacks (like this gem does: https://github.com/asee/mixable_engines from this thread: Extending controllers of a Rails 3 Engine in the main app)
1) load YourEngine::Engine.config.root + 'app' + 'controllers' + 'your_controller' inside your_controller.rb that is in #{main_app}/app/controller/your_engine folder. Notice load instead of require.
2) Devise way (according to some SO topics suggest): In main app create new controller that subclasses engine's one + edit routes to they point to this new controller.
I am still sure some even better solutions exist. Please correct me if they do!
Upvotes: 4
Views: 3841
Reputation: 2909
I know this is a very old question but in case someone else finds this question, here is a gem that does decorators nicely. It hooks into Rails ActiveSupport and adds a convention to doing decorators that is safe from circular dependencies. We have been using it in production on multiple apps for a while.
https://github.com/EPI-USE-Labs/activesupport-decorators
Upvotes: 1
Reputation: 115511
Your option 2) is fine because it will let you upgrade the gem seamlessly.
Your current way simply overrides the existing controller.
Say you want to extend FooController
.
Create a file named foo_controller_decorator.rb
in your initializer folder
In the file:
FooController.class_eval do #your additionnal code here. end
Upvotes: 5