6

I'm in the proces of converting my standard Rails app to an mountable engine. The app is comparable to a standard blogging app and i want every model, controller and view to be extendable hence my choice for a mountable engine.

One of the gems i use is Devise which is as far as i understand a sort of a mountable engine itself. It can be used inside a mountable engine as stated here.

I'm able to use it partially within my engine. Everything is working fine including some Devise controller i override like this one:

# config/routes.rb

Bbronline::Engine.routes.draw do
  devise_for :users, class_name: "Bbronline::User", module: :devise,
    controllers: { registrations: "bbronline/devise_overrides/registrations"}
    ...

# controllers/bbronline/devise_overrides/registrations_controller.rb
require_dependency "bbronline/application_controller"

module Bbronline

class DeviseOverrides::RegistrationsController < Devise::RegistrationsController

  def new_intermediair
    @user = User.new
  end
  ...

The correct view 'views/bbronline/devise_overrides/registrations/new_intermediair.html.haml' is also correctly loading as expected.

However my issue is that the views that i override without a custom controller are not properly loaded. For example the view that should the login view is located in views/bbronline/devise/sessions/new.html.haml and is not loaded. Instead the standard Devise login view gets loaded i.e. devise-2.1.0/app/views/devise/sessions/new.html.erb

Of course i could solve this problem by overriding every controller with my own controller like i did with the registrations_controller above but this seems very ugly. Is overriding every controller the way to do this? Is there a more convenient way to override views from an mountable engine from within another mountable engine?

prusswan
  • 6,853
  • 4
  • 40
  • 61
Harm de Wit
  • 2,150
  • 2
  • 18
  • 24

3 Answers3

7

If you don't want to adjust the config.railties_order in every app that uses your engine, just require 'devise' on top of your lib\my_engine\engine.rb file.

wintersolutions
  • 5,173
  • 5
  • 30
  • 51
  • 1
    While the other answers offer insight to exploring the view_paths, this is the answer if your engine is meant for loading and customizing other engines – prusswan Nov 15 '13 at 09:55
4

The view_paths are in incorrect order. Checking the view paths of Devise::SessionsController shows:

Devise::SessionsController.view_paths 
=> #<ActionView::PathSet:0x007fa1bf0e36f8 @paths= [/Users/harmdewit/Dropbox/Code/projects/brightin/bbr-online/bbr-online-gem/test/‌​dummy/app/views, 
/Users/harmdewit/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/devise-2.1.‌​0/app/views, 
/Users/harmdewit/Dropbox/Code/projects/brightin/bbr-online/bbr-online-gem/app/vi‌​ews]> 

The last path of the mountable engine should come before the middle devise path. The solution is setting the loading priority in application.rb like this:

#test/dummy/config/application.rb (the app that uses my mountable engine)
...
config.railties_order = [Blog::Engine, :main_app, :all]
...

This is also documented in the rails api: http://api.rubyonrails.org/classes/Rails/Engine.html#label-Loading+priority

Thanks to José Valim for pointing in the right direction.

Harm de Wit
  • 2,150
  • 2
  • 18
  • 24
  • 2
    Any way I could make this change without having to change the configuration of my dummy application? I'd prefer to make this the default behavior whenever I load my gem. – Ajedi32 Mar 10 '13 at 18:39
1

I need more information. Which controller are you defining and from which controller is it inheriting from? Which view is being rendered and which one did you expect to render? Also, .view_paths is your friend so try in your rails console the following:

Devise::SessionsController.view_paths
YourApp::SomeDeviseController.view_paths

This will give you a better idea of where each controller is searching for templates.

José Valim
  • 50,409
  • 12
  • 130
  • 115
  • I'm not defining a controller, i just want to override the view. More specifically i want to override the view located in `devise-2.1.0/app/views/devise/sessions/new.html.erb` without overriding the controller. Is this possible? – Harm de Wit Jun 29 '12 at 10:03
  • Oh .view_paths shows: Devise::SessionsController.view_paths => # Bbronline::SessionsController does not exists of course, i do not override it – Harm de Wit Jun 29 '12 at 10:04
  • 1
    If you don't want to use a custom controller, just override the view, just place your new view at: `your-engine/app/views/devise/sessions/new.html.erb` and make sure Devise's engine is loaded before your mountable engine (just require devise before). Again, calling `.view_paths` in your `Devise.parent_controller` or in your application controller will tell you the template lookup order. – José Valim Jun 29 '12 at 10:07
  • Hrm, I can see that the devise view paths is coming *before* your engine one, that's why you can't override it. Try mangling with the load order or manually manipulating the `.view_paths` in your `Devise.parent_controller` or your application controller. – José Valim Jun 29 '12 at 10:10