Mountable Engines and ApplicationControllers

I’ve been messing around with mountable engines and I crossed a dilemma that I am sure you faced when implementing them, what should ApplicationController inherit from? Today each engine has a unique, name spaced ApplicationController, all of which inherit from ActionController::Base, then all of the controllers in each engine inherit from their corresponding ApplicationController. I understand the need to set up the engines this way so that they can run outside of the main_app, but all of the controllers in Rails inherit from ApplicationController because they need to share code. What primarily comes to mind are authentication methods and session variables, i.e. current_user. So when creating a Rails app that uses mountable engines, it is nice for all of the things to access a common ancestor. One solution is to include modules in ActionController::Base, as it is a common ancestor to all the controllers in the app. This process is outlined in this blog:

http://www.cowboycoded.com/2011/02/11/working-with-applicationcontroller-in-a-rails-3-engine/

While this works it has in my opinion two problems –

  1. there is not a convention on where to put the module that gets included on ActionController::Base

  2. because the module gets included on initialization, you have to restart your Rails app for any changes to take effect

What I have done to combat these issues is create an EnginesController that inherits from ActionController::Base, then have each of my engines’ ApplicationControllers inherit from EnginesController. This seems to solve the above issues as long as EnginesController is in the load path.

So my questions for the group are, does this seem like a reasonable solution or am I missing something like, this is why ActionController::Base exists and why don’t you just open class it in the load path for the same effect? And if this is a reasonable approach, is it worth considering a convention on where to put files that are shared among mountable engines and the main_app?

Thanks for your time and thoughts,

Scott

It looks like a reasonable solution for your case, but I don’t think that it would be good to make it default in Rails.

What you could do to make it simpler is creating module as you proposed, but don’t require it on initialization, you could simply require it in ApplicationController files and include there.

I’ve been developing engines (Forem: https://github.com/radar/forem and Spree: https://github.com/spree/spree) for a while, and I’ve always chosen to make the engine’s ApplicationController inherit from the application’s ApplicationController for the reasons you point out: you get access to all the typical methods like current_user and so on from the application’s ApplicationController.

I can’t think of any other way to make that happen.

I’ve been developing engines (Forem: https://github.com/radar/forem and Spree: https://github.com/spree/spree ) for a while, and I’ve always chosen to make the engine’s ApplicationController inherit from the application’s ApplicationController for the reasons you point out: you get access to all the typical methods like current_user and so on from the application’s ApplicationController.

Hm, doesn’t that break the concept of encapsulation in an engine, Ryan? If I inherit my engine’s controller from the “hosting” app’s controller I’m creating implicit dependencies: I assume that the “host” app provides, e.g. devise methods in the controller. These requirements are not declared anywhere.

I like the modules that are included into the engine’s ApplicationController (should be called EngineController, as Scott proposed). That way it is clearly visible what dependencies the engines has.

Ok now i know why i can’t delete application_controller.rb from my applications with Spree. It was a bit confusing since I don’t use It.