简体   繁体   中英

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

Have you set up your config/routes.rb with the following.

devise_for :users do
    get 'logout' => 'devise/sessions#destroy'
    get 'changepassword' => 'devise/registrations#edit'
    get 'access' => 'homepages#access'
    get 'history' => 'policies#history'
    get 'future' => 'policies#future'
  end
  devise_for :users, :controllers => { :sessions => :sessions }
  resources :users

I have the same problem. I set the routes then it was worked for me :)

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.

I don't like using get "/account/password" or a path in my spec. Seems hacky. I fixed a similar problem by using better syntax in my routes.rb file:

  1. Using path: 'account' option in devise_for
  2. Explicitly setting my custom controller with controllers: {registrations: 'registrations'}

So my routes.rb looks like this:

devise_for  :users, 
            path: 'account', 
            path_names: {sign_in: 'login', sign_out: 'logout', sign_up: 'register'},                 
            controllers: {registrations: 'registrations'},
            skip: [:passwords]

Then I can use get :new in my test. Much cleaner.

Hope this helps someone else.

I am using devise 3.0.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM