I've been using rails 3 engines and (at least in my experience) the engine's application controller is overidden by the app's application controller. Wouldn't it be better if the app would just load on top of the engine?
I mean that if an engine's application controller has methods or anything else that does not collide with the stuff defined with the app, couldn't it be used?
Isn't this the default behaviour of ruby, that you can just reopen a class and add methods to it possibly overriding them but not deleting the rest of the class?
Indeed, the application’s app/controllers/application_controller.rb will take precedence over a similarly named file in the engine. The same goes for anything else in the app directory, too.
This is why you namespace your engine: to avoid collisions such as these.
Ok. So now I’ve namespace my ApplicationController like so:
class Citygate::Admin::ApplicationController < ::Admin::ApplicationController
protect_from_forgery
layout ‘admin/application’
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_url, :alert => exception.message
end
end
The problem here is that I want the app/admin/application_controller.rb to be able to change the cancan redirect and since the engine’s controller inherits from it, the engine’s definitions will always take precendence. This is not the functionality I want. I want to be able to provide some defaults in the engine that can be overidden in the app.
If you just merged the ApplicationControllers, then the code in the last loaded engine would take precedence in the main app and all other engines. And if you overwrote some methods in one engine and others in another you would quickly have a quagmire.
Using inheritance provides a nice predictable way to change behavior. This way you main application stays unaltered and each engine can access this code and change its behavior without affecting the main app or other engines.
Insert some warning about why it would be better to change the code in your main app here. But, if you want to change it in your engine you can. Something like
class ::Admin::ApplicationController
do your monkey patching here
end
Just make sure this is in a file that gets loaded when your engine loads – I would suggest an initializer, but …
Your monkey patch will allow me to change the app from the engine. But my idea was to change the engine from the app.
Maybe this could be solved some other way, since my problem is as simple as wanting to set some defaults in the engine’s application controller and allowing the app to change those defaults easily (eg. overwriting them in its own application controller).
Is there a better way of doing this?
BTW, the engine’s routes.url_helpers are not loaded in rspec and cucumber tests by default. It feels kind of hackish to load them myself. Wouldn’t it be possible to correct this or is it a feature?