How can I make routes from a Rails 3 engine available to the host application?

13,561

Solution 1

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:

Solution 2

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

Solution 3

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

Share:
13,561

Related videos on Youtube

PerfectlyNormal
Author by

PerfectlyNormal

Updated on September 20, 2020

Comments

  • PerfectlyNormal
    PerfectlyNormal over 3 years

    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).

  • PerfectlyNormal
    PerfectlyNormal over 13 years
    Doing that, removing the mount-call in my app-routes, and scoping in engine-routes (scope '/engine' do) and everything works. Thanks a lot :)
  • bowsersenior
    bowsersenior over 13 years
    Cool, thanks for the info on the other steps needed to get the Engine routes working.
  • Xavier Shay
    Xavier Shay about 12 years
    For Rails 3.1 and later, remove the map parameter to the block (just remove the entire |map| part).
  • Jwan622
    Jwan622 almost 8 years
    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?
  • bowsersenior
    bowsersenior almost 8 years
    @Jwan622 Not sure about that. There may be some useful info in this answer: stackoverflow.com/a/7040520/457819
  • Jwan622
    Jwan622 over 7 years
    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?
  • Alexander Kuznetsov
    Alexander Kuznetsov over 7 years
    Jwan622, for the own routes you can use helpers without any prefixes.
  • 0xtobit
    0xtobit over 6 years
    Unfortunately, the blog post link seems to be dead.
  • bowsersenior
    bowsersenior over 6 years
    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.