23

I have a Rails 3 application with several engines containing additional functionality. Each engine is a separate service that customers can purchase access to.

I am, however, having a problem with routes from the engines that aren't readily available to the controllers and views.

controller:

class ClassroomsController < ApplicationController
  ..
  respond_to :html

  def index
    respond_with(@classrooms = @company.classrooms.all)
  end

  def new
     respond_with(@classroom = @company.classrooms.build)
  end

  ..
end

app/views/classrooms/new.html.haml:

= form_for @classroom do |f|
  ..
  f.submit

config/routes.rb in engine:

MyEngineName::Engine.routes.draw do
  resources :classrooms
end

config/routes.rb in app:

Seabed::Application.routes.draw do
  mount MyEngineName::Engine => '/engine'
  ...
end

lib/my_engine_name.rb in engine:

module MyEngineName
  class Engine < ::Rails::Engine
  end
end

attempting to go to /classrooms/new results in

NoMethodError in Classrooms#new

Showing app/views/classrooms/_form.html.haml where line #1 raised:
  undefined method `hash_for_classrooms_path' for #<Module:0x00000104cff0f8>

and attempting to call classrooms_path from any other view results in the same error. I can, however, call MyEngineName::Engine.routes.url_helpers.classrooms_path and get it working. I'm thinking I might have defined the routes wrong, but can't find another way that works.

Tried running the app with both Passenger (standalone and Apache module) and WEBrick (rails server). Using latest Rails from Git (7c920631ec3b314cfaa3a60d265de40cba3e8135).

tshepang
  • 10,772
  • 21
  • 84
  • 127
PerfectlyNormal
  • 4,053
  • 2
  • 32
  • 45

3 Answers3

26

I had the same problem, and found this in the documentation:

Since you can now mount an engine inside application’s routes, you do not have direct access to Engine‘s url_helpers inside Application. When you mount an engine in an application’s routes, a special helper is created to allow you to do that. Consider such a scenario:

# config/routes.rb
MyApplication::Application.routes.draw do
  mount MyEngine::Engine => "/my_engine", :as => "my_engine"
  get "/foo" => "foo#index"
end

Now, you can use the my_engine helper inside your application:

class FooController < ApplicationController
  def index
    my_engine.root_url #=> /my_engine/
  end
end
davidrac
  • 10,318
  • 3
  • 35
  • 70
  • for code inside the Engine, do you need to prepend routes to its own controllers with the engine's name as well? Or can you just use `classrooms_path` from inside the Engine? – Jwan622 Aug 31 '16 at 19:53
  • Jwan622, for the own routes you can use helpers without any prefixes. – Alexander Kuznetsov Oct 18 '16 at 15:45
25

Change config.routes in your engine to:

Rails.application.routes.draw do  # NOT MyEngineName::Engine.routes.draw
  resources :classrooms
end

The way you have it, the routes are only available in the MyEngineName::Engine namespace and not in the rest of the host rails application.

There used to be a blog post with more info, but unfortunately it is no longer available:

bowsersenior
  • 12,000
  • 2
  • 44
  • 51
  • Doing that, removing the mount-call in my app-routes, and scoping in engine-routes (`scope '/engine' do`) and everything works. Thanks a lot :) – PerfectlyNormal Dec 06 '10 at 00:57
  • Cool, thanks for the info on the other steps needed to get the Engine routes working. – bowsersenior Dec 06 '10 at 03:27
  • 2
    For Rails 3.1 and later, remove the `map` parameter to the block (just remove the entire `|map|` part). – Xavier Shay Feb 25 '12 at 00:21
  • 1
    What if I have a catch-all route at the bottom of my main app? How do I ensure these engine's routes are not just appended to the bottom of the host app's routes? – Jwan622 Jul 28 '16 at 20:14
  • @Jwan622 Not sure about that. There may be some useful info in this answer: http://stackoverflow.com/a/7040520/457819 – bowsersenior Aug 01 '16 at 17:48
  • Unfortunately, the blog post link seems to be dead. – 0xtobit Sep 18 '17 at 19:25
  • Thanks for letting me know. Couldn't find a new URL for the blog post. Let me know if you find one. Added a note to the answer to indicate the link was down. – bowsersenior Sep 19 '17 at 21:40
2

For me also help to add

require 'engine' if defined?(Rails)

to my main gem file (lib/.rb).

Good example - https://github.com/mankind/Rails-3-engine-example/blob/master/lib/dummy.rb