Engine routes in Application Controller

Olives picture Olives · Sep 28, 2011 · Viewed 8.3k times · Source

I have a before_filter hook in my main app's application controller that does something like: (It doesn't just put a link in the flash, there is a message, but it isn't relevant to the question, it just accesses the route in the method)

class ApplicationController < ActionController::Base
  before_filter :set_link

  def set_link
    flash[:notice] = items_path
  end
end

This works fine for the app, however when I go into the controllers for an engine I made I get the exception

No route matches {:controller=>"items", :action=>"index"}

I understand that when in the engine, the routes helpers are for the engine unless prefixed with main_app

So changing the method in the application controller to

  def set_link
    flash[:notice] = main_app.items_path
  end

Gets rid of the exception but I really don't want to have to do that. Is there another solution to getting the engine to recognize the main_app routes?

EDIT:

This also happens if the application layout calls path helpers. So if the engine is designed to integrated into the main_app's layout then this issue will crop there up too.

Answer

Benoit Garret picture Benoit Garret · Oct 1, 2011

Mountable engines are designed to work like this, that is isolate the main app routes and the engine routes.

If you want the two sets of routes to be merged, you can use a non-isolated engine. The first step is removing the isolated_namespace method call in your engine definition:

module MyEngine
  class Engine < Rails::Engine
    isolate_namespace MyEngine # remove this line
  end
end

The second step is to convert your routes in my_engine/config/routes.rb, you should go from this:

MyEngine::Engine.routes.draw do
  # stuff that routes things
end

to this:

Rails.application.routes.draw do
  # stuff that routes things
end

and remove the mount method call in your application's routes:

App::Application.routes.draw do
  mount MyEngine::Engine => "/engine" # remove this line
end

The main advantages of doing it this way would be:

  1. No need to monkey-patch rails. I know devise does this, but this could be a leftover from the days when engines didn't exist in rails.

  2. No need to mount the engine in the application routes. On the other hand, this could backfire if you'd like to control more precisely the insertion point as all you engine routes would be called after (or before, I don't have the answer to this question) your main routes.

If you're looking for documentation on engines, the rails docs for the Engine class are a pretty good starting point. I'd strongly recommend that you read them (in case you haven't yet) if you're interested in the subject.