Reputation: 1185
I've got an isolated, mountable rails engine which mounts itself in a namespace that is already declared in the host application. Here's how it looks more or less:
routes.rb in the plugin:
# my_engine/config/routes.rb
MyEngine::Engine.routes.draw do
namespace :admin do
resources :some_resource
end
end
And the appropriate snippet from the host app's routes.rb:
# config/routes.rb
mount MyEngine::Engine, at: "/"
namespace :admin do
resources :host_resource
end
I'm mounting the engine at /
since there are some routes in the engine that should be available there, and the admin namespaces overlap is intentional.
These routes generates several path helpers, including my_engine.admin_some_resources_path
and what I would expect to be admin_host_resources_path
. The latter is what doesn't work.
Assume there's a controller in the main application that is declared so:
# app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ApplicationController
layout 'admin'
end
And the engine's AdminController is declared in such a way as to inherit from it:
# my_engine/app/controlles/admin/application_controller.rb
class MyEngine::Admin::ApplicationController < Admin::ApplicationController
end
So far, all that works as expected. Now, assume that in the main application's admin
layout, referenced from the Admin::ApplicationController, I try to use something essentially like:
# app/views/layouts/admin.html.erb
<%= link_to "Host resources", admin_host_resources_path %>
<%= link_to "Plugin's resources", my_engine.admin_some_resources_path %>
This works fine when I load a path like '/admin/host_resources' - it renders the admin layout from the main application no problem. When opening the path '/admin/some_resources' - which goes into the plugin - it stops working complaining that admin_host_resources_path
was not found. It starts working when I change it to this:
# app/views/layouts/admin.html.erb
<%= link_to "Host resources", main_app.admin_host_resources_path %>
<%= link_to "Plugin's resources", my_engine.admin_some_resources_path %>
Which is not what I want, nor is it what I expect. Also I've seen enough rails plugins to know that this shouldn't be necessary, but after reading the Engines documentation I'm still at a loss. I've also scoured Stack, but to no avail. My question is: how to include the main_app helpers so that the prefix main_app is no longer needed?
It's worth noting that the views for host_resource are in the main application itself, while the views for some_resource are in the engine. This shouldn't matter though, since the view which doesn't work is the admin
layout in the main application.
Also excuse the heavily anonymised code, but this is required of me.
Upvotes: 4
Views: 2775
Reputation: 933
Add this in your controller:
helper Rails.application.routes.url_helpers
Upvotes: 6
Reputation: 1185
I found an answer to my question here: http://candland.net/2012/04/17/rails-routes-used-in-an-isolated-engine/
What I needed to do was to specify a helper like this in the engine:
module MyEngine
module ApplicationHelper
def method_missing method, *args, &block
if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
if main_app.respond_to?(method)
main_app.send(method, *args)
else
super
end
else
super
end
end
def respond_to?(method)
if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
if main_app.respond_to?(method)
true
else
super
end
else
super
end
end
end
end
Then make sure it is loaded when the engine is loaded by adding this to my engine class:
initializer 'my_engine.action_controller' do |app|
ActiveSupport.on_load :action_controller do
helper MyEngine::ApplicationHelper
end
end
Thanks to this the paths that can be served by the engine are served by the engine, and everything else is sent to the main_app helper.
Upvotes: 3