Search code examples
ruby-on-railsruby-on-rails-3rspecrspec2rspec-rails

ActionController::RoutingError when test custom devise controller


I'm trying to add a custom action to Devise's registration controller which allows users to change their passwords (I cannot use default registrations#edit since I need a form for changing only password, not email/username). The implementation I wrote below works in development mode but I get this error when I test controller.

Failure/Error: get 'password'
ActionController::RoutingError:
  No route matches {:controller=>"registrations", :action=>"password"}

There is my code (I tried to skip unrelated parts)

spec/controllers/registrations_controller_spec.rb

describe RegistrationsController do
  include Devise::TestHelpers

  before :each do
    request.env["devise.mapping"] = Devise.mappings[:users]
  end

  describe "GET 'password'" do
    it "..." do
                     # The problem is here,
      get 'password' # it raises ActionController::RoutingError
    end
  end
end

app/controllers/registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController
  # ...
  def password
  end
end

config/routes.rb

devise_for :users, path: 'account', 
  controllers: { registrations: 'registartions' }, 
  skip: [:registartions, :sessions]

devise_scope :user do
  # ...
  scope '/account' do
    get 'password' => 'devise/registartions#password', as: "change_password
  do
end

spec_helper.rb

# ...
RSpec.configure do |config|
  # ...
  config.include Devise::TestHelpers, :type => :controller
end

Solution

  • I would usually add a comment for this, but I'm including a code block and it gets messy in comments.

    It seems like you're trying to preform a GET on /password instead of on /account/password.

    From what I'm reading, you've got a mapping for /account/password:

    devise_scope :user do # used to remove /users/ part from devise URLs
      # ...
      scope '/account' do # adds /account to URLs
        get 'password' => 'devise/registartions#password', as: "change_password"  
        # this will match /account/passwordAnswer
    
      do
    end
    

    So you should either remove the scope, or replace your get request in test with this:

    get "/account/password", :user => @user
    

    or this

    get change_password_path(@user)
    

    Where @user is a User's mock.

    Run rake routes to confirm.