4

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!

Community
  • 1
  • 1
Stanislav Pankevich
  • 11,044
  • 8
  • 69
  • 129
  • Might this be a namespace issue? Just a guess, but if Ruby is seeing a MessagesController object within your Rails app namespace, it is going to use it for any method calls within that namespace. – coreyward Oct 10 '11 at 23:10

2 Answers2

5

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.

  1. Create a file named foo_controller_decorator.rb in your initializer folder

  2. In the file:

FooController.class_eval do
  #your additionnal code here.
end
apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • Thanks for the answer. I know I can do it this way. I am just wondering why it is being overriden because of how then this could be done in devise - https://github.com/plataformatec/devise/wiki/How-To:-Change-the-redirect-path-after-destroying-a-session-i.e.-signing-out? (overriding only one action) – Stanislav Pankevich Oct 10 '11 at 23:24
  • In this case, your app defines the ApplicationController and some actions are included inside unless you already defined it. – apneadiving Oct 10 '11 at 23:29
  • To use the same logic, create a module with your addtional action and include it in the desired controller – apneadiving Oct 10 '11 at 23:30
  • Yes, you're right. Now I understand that my citation from devise was unrelevant. Nevertheless, the topic question remains the same. – Stanislav Pankevich Oct 11 '11 at 03:20
1

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

Pierre Pretorius
  • 2,869
  • 22
  • 21