Search code examples
ruby-on-rails-3.2functional-testingrails-enginesrails-admin

Rails 3.2 Engines - routes not working in test cases


I mounted in my app the RailsAdmin engine ( according to the instructions from the wiki ) using

mount RailsAdmin::Engine => '/backend', :as => 'rails_admin'

I had to extend one controller from the engine to add a before_filter. When running my app in development, my extension and the other engine features are working perfectly.

However I have an issue in writing functional tests using Test::Unit for my before_filter. The filter kicks in at the right moment and works as expected, but once the action "tweaked" by the before filter redirects to index ( which is an expected result ), I get the following routing error:

ActionController::RoutingError: No route matches {:controller=>"rails_admin/main"}

The code leading to the exception lies in the engine's method to redirect to index or to the previous page ( kind of referer ); here is the code for the method

def back_or_index

if params[:return_to].presence

params[:return_to]

else

index_path

end

I discovered that when running the app in development, the url_for call triggered by index_path is supplied with the proper path_segments ( i.e.: :model_name => 'user' ) so that the route below is matched

   index GET|POST    /:model_name(.:format)                 rails_admin/main#index

On the other hand, when running the tests, the path_segments are not supplied, thus the :model_name constraint is not satisfied when looking for a matching route.

Since I'm new to engines, can someone tell me what I'm missing?

To me it looks as if the engine should take into consideration the fact that is mounted generating the index_path, but as I said I'm not an expert in this....


Solution

  • use_route was not enough: the call to index_path was failing anyway.

    After lots of debugging, I am not yet completely sure about the root cause of why the same code was not working both in test and development.

    What I observed is that index_path in development is able to infer the model_name from the url of the request, while in test is is not.

    Although ugly, my solution was to override the method as follows in app/controllers/rails_admin/main_controller.rb

    module RailsAdmin
     class MainController
    
            # Override to fix a routing error when running tests
        def back_or_index
          if params[:return_to].presence && params[:return_to].include?(request.host) && (params[:return_to] != request.fullpath)
            params[:return_to]
          else
            # forward :model_name as default_url_options is not aware of it in tests
            index_path( :model_name => params[:model_name] )
          end
        end
    
     end
    end
    

    In my controller specs for MainController I do the following

    put :edit, { :model_name => 'user', :id => root.id, :user => { :role => :root }, :use_route => :rails_admin }
    

    And this is what I have in my routes

      devise_for :users
      mount RailsAdmin::Engine => '/backend', :as => 'rails_admin'
      mount Rich::Engine => '/rich', :as => 'rich'
    

    If anyone has a better solution, sharing would be really appreciated!