44

I'm making a small rails engine which I mount like this:

mount BasicApp::Engine => "/app"

Using this answer I have verified that all the routes in the engine are as the should be:

However - when I (inside the engine) link to a named route (defined inside the engine) I get this error

undefined local variable or method `new_post_path' for #<#<Class:0x000000065e0c08>:0x000000065d71d0>

Running "rake route" clearly verifies that "new_post" should be a named path, so I have no idea why Rails (3.1.0) can't figure it out. Any help is welcome

my config/route.rb (for the engine) look like this

BasicApp::Engine.routes.draw do
  resources :posts, :path => '' do
                resources :post_comments
                resources :post_images
        end
end

I should add that it is and isolated engine. However paths like main_app.root_path works fine - while root_path does not

Community
  • 1
  • 1
Markus
  • 2,306
  • 3
  • 23
  • 34
  • 1
    If you got here because you're having issues with the Blogit gem - you can ignore the solutions below (which do work for other apps) and go to your blogit.rb file and uncomment the line that says: config.inline_main_app_named_routes = true – Ecnalyr Sep 19 '13 at 12:54

3 Answers3

60

The right way

I believe the best solution is to call new_post_path on the Engine's routes proxy, which is available as a helper method. In your case, the helper method will default to basic_app_engine, so you can call basic_app_engine.new_post_path in your views or helpers.

If you want, you can set the name in one of two ways.

# in engine/lib/basic_app/engine.rb:
module BasicApp
  class Engine < ::Rails::Engine
    engine_name 'basic'
  end
end

or

# in app/config/routes.rb:
mount BasicApp::Engine => '/app', :as => 'basic'

In either case, you could then call basic.new_posts_path in your views or helpers.

Another way

Another option is to not use a mounted engine and instead have the engine add the routes directly to the app. Thoughtbot's HighVoltage does this. I don't love this solution because it is likely to cause namespace conflicts when you add many engines, but it does work.

# in engine/config/routes.rb
Rails.application.routes.draw do
  resources :posts, :path => '' do
                resources :post_comments
                resources :post_images
  end
end

# in app/config/routes.rb:
# (no mention of the engine)
James A. Rosen
  • 60,042
  • 58
  • 173
  • 260
15

On Rails 4 the engine_name directive did not work for me.
To access a named route defined in engine's routes from engine's own view or controller, I ended up using the verbose

BasicApp::Engine.routes.url_helpers.new_post_path

I recommend defining a simple helper method to make this more usable

# in /helpers/basic_app/application_helper.rb

module BasicApp::ApplicationHelper
  def basic_app_engine
    @@basic_app_engine_url_helpers ||= BasicApp::Engine.routes.url_helpers
  end
end

With this in place you can now use

basic_app_engine.new_post_path

In case you need to access your main application helper from the engine you can just use main_app:

main_app.root_path
Epigene
  • 2,873
  • 1
  • 20
  • 28
  • 1
    AFAIK `BasicApp::Engine.routes.url_helpers` generates a new `Module` and defines all the path/url helper methods every time you invoke it. It can quickly become a performance and memory problem. So I'd recommend including it in the class where you want to use it. – tmichel May 25 '16 at 09:33
  • @tmichel is right, memoization must be used to avoid Module generation on very call. Try (untested!) `return @@basic_app_engine_url_helpers ||= BasicApp::Engine.routes.url_helpers` – Epigene Jun 19 '17 at 11:43
  • neither of the solutions in the "right way" above worked for me. Mounting the engine routes as '' just created what looks like a copy of main_app, or at least an object with the same methods. This way does what the others should, but I'm still curious why the others don't work. – Fred Willmore Apr 13 '21 at 00:41
4

use the below in you app to access the engine routes

MyApp::Engine.routes.url_helpers.new_post_path
edrich13
  • 382
  • 2
  • 12