ActionController::UrlGenerationError for devise registration controller - ruby-on-rails

I'm running into an interesting ActionController::UrlGenerationError while testing my custom devise User::RegistrationsController
Here's the error:
ActionController::UrlGenerationError:
No route matches {:action=>"create", :controller=>"user/registrations", :user=>{:name=>"Adriane Koepp", :city=>"Nidiafurt", :address=>"14955 Cormier Viaduct", :country=>"Mozambique", :email=>"moshe#kozey.com", :phone_primary=>"(295) 491-0447 x9108", :phone_secondary=>"536.985.9499 x7264", :postal_code=>"93438-7448", :province=>"South Carolina", :password=>"MaH9R5G8XqB", :pets_attributes=>[{:name=>"Patches", :chip_number=>"149793073311890", :species=>"iusto"}]}}
The error shows up in all my tests for this controller, but for simplicity, I'll only list one test for the create action:
it 'creates a new User' do
expect do
post :create, params: { user: valid_attributes }
end.to change(User, :count).by(1)
end
The routes.rb contains:
devise_for :users, controllers: {
registration: 'user/registration'
}
I can navigate to my registration page just fine at http://localhost:3000/users/sign_up, but for some reason, my tests don't seem to think this controller has a valid URL for the create action. Why so?
Additional steps
Upon following D1ceWard's suggestion, I pluralized "registration" in my routes, and now the error message changed to a AbstractController::ActionNotFound error. I countered that by following the documentation and added the following block to the top of my tests:
before(:each) do
#request.env['devise.mapping'] = Devise.mappings[:user]
end

Your error is caused by missing pluralization, devise don't know what registration is, but work with registrations.
Solution :
# routes.rb
devise_for :users, controllers: {
registrations: 'user/registrations'
}
You can use rails routes to check all existings routes.
Devise doc about custom controllers

Related

Rspec tests not finding matching routes

I'm getting unexpected errors when running some Rspec tests. They are
1) PeopleController redirects when loading root should redirect to the splash page
Failure/Error: get '/'
ActionController::UrlGenerationError:
No route matches {:action=>"/", :controller=>"people"}
...
2) PeopleController redirects when loading /people/show should redirect to the base person path
Failure/Error: get '/show' #/show
ActionController::UrlGenerationError:
No route matches {:action=>"/show", :controller=>"people"}
I don't understand why Rspec can't find the routes.
From the controller, people_controller.rb:
class PeopleController < ApplicationController
...
def show
redirect_to people_path
end
def index
#people = Person.all
end
...
From the Rspec file people_controller_spec.rb:
describe PeopleController do
describe "redirects" do
context "when loading root" do
it "should redirect to the temp page" do
get '/'
last_response.should be_redirect
follow_redirect!
last_request.url.should include('/temp')
end
end
context "when loading /people/show" do
it "should redirect to the base people path" do
get '/people/show'
last_response.should be_redirect
follow_redirect!
last_request.url.should include('/people')
end
end
end
end
And my routes:
$ rake routes
Prefix Verb URI Pattern Controller#Action
...
person GET /people/:id(.:format) people#show
...
root GET / redirect(301, /temp)
routes.rb:
Rails.application.routes.draw do
resources :temp
resources :people
# map '/' to be a redirect to '/temp'
root :to => redirect('/temp')
end
What am I missing to get the routes from test to match up? I could see the root test not working because it's not technically handled by the People controller (I tried putting it in as a sanity test and only made myself more confused) but the /show failure really makes no sense to me.
Inside a controller test the method get takes an action argument, not a path. If the resource is a member (as opposed to a collection), you must also specify the id parameter, so:
get :show, id: 1
will call the #show action on an instance of PeopleController, with a params hash including {id: '1'}.
This is described in more detail in the Guide to Testing Rails Applications.

Could not find devise mapping for controller path

I know there are a ton of questions with this same problem but none of the solutions seem to be working for my situation.
I've defined my own sessions, registrations, and users controllers since I'm using an API with token authentication, but I can't seem to get my routes/scoping working.
I get the following error message upon trying to run an Spec test on my sessions controller (which inherits from DeviseController)
Failure/Error: post :create, credentials
AbstractController::ActionNotFound:
Could not find devise mapping for path "/api/v1/sessions/create?user_login%5Bemail%5D=rosina%40russel.name&user_login%5Bpassword%5D=12345678".
This may happen for two reasons:
1) You forgot to wrap your route inside the scope block. For example:
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
2) You are testing a Devise controller bypassing the router.
If so, you can explicitly tell Devise which mapping to use:
#request.env["devise.mapping"] = Devise.mappings[:user]
I've actually done both of these things based on other answers that I've read, but I don't think its done correctly for my specific situation.
Here is the spec test I'm trying to run
describe "POST #create" do
before(:each) do
#user = FactoryGirl.create :user
#user.skip_confirmation!
#request.env['devise.mapping'] = Devise.mappings[:user]
end
context "when the credentials are correct" do
before(:each) do
credentials = { user_login: { :email => #user.email, :password => "12345678"} }
post :create, credentials
end
it "returns the user record corresponding to the given credentials" do
#user.reload
user_response = JSON.parse(response.body, symbolize_names: true)
expect(user_response[:auth_token]).to eql #user.auth_token
end
it { should respond_with :created }
end
end
As you can see, I'm specifying what it's saying that I haven't specified.
Here is the snippet from my routes.rb before the definition of my API in it's namespace:
namespace :api, defaults: { format: :json } do
namespace :v1 do
devise_for :users, skip: [:sessions, :registrations]
devise_scope :user do
post 'sessions', to: 'sessions#create'
delete 'sessions', to: 'sessions#destroy'
end
If anyone sees anything from with this please let me know, I'd love to test my controller...
And yes, my sessions_controller is located in app/controllers/api/v1/sessions_controller.rb and it is properly defined as class API::V1::SessionsController < DeviseController
I noticed that devise_for is supposed to SET Devise.mapping but that seems to not be happening at all!
I should've done this right away. I sent Devise.mappings.inspect to the logger and it read that the mapping was stored in :api_v1_user so the key in the mapping hash corresponds to the namespace that you wrote devise_for in... hopefully this will help others
Based on your routes, API is in json format. So you need to specify that when sending post method. Which is why I think rspec is complaining about that route not existing because it doesn't know to use json. Try changing this
post :create, credentials
to this
post :create, credentials, format: :json

In Rails 4 How to Test Devise Custom Registration Paths?

I have customized the devise paths like this :
devise_for :users, path: '', path_names: { sign_in: 'signin', sign_out: 'signout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'signup', sign_up: 'new' }
So for example it makes the user signup path like this http://localhost:3000/signup/new. Now the problem is, I don't know how to test this page. Here's the test for users_controller :
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
test "should get signup" do
get :signup_new
assert_response :success
assert_select "title", "SignUp | #{Figaro.env.app_name}"
end
end
How to visit these custom paths in my test files?
You are probably testing the wrong controller. Check your routes (rake routes) to see which controller is assigned to handle your Devise authentication routes. By default I believe it is Devise::SessionsController.
I do not think this is your intent, but it is worth mentioning that you should not test the devise gem.
Note that requests for ActionController::TestCase are simulated. If you want to test true requests then you should look into integration testing. A brief overview can be found here
UPDATE
Take a look in the Devise gem for some examples of how to log a user in here. Notice that include Devise::TestHelpers is added near the top of the test class which adds a sign_in method.

How to test extended functionality after devise sign_up action?

Apparently I have a unique situation that I can't find help with anywhere. I'm trying to extend my sign up process to create extra models in my database. Here is a basic flow of what I'd like to do:
User Signs up with Email/Password (along with other model values)
System creates a 'User' model
System creates a 'Profile' model
System creates a 'Company' model
System creates an 'Account' model
The biggest challenge is that I'm using Devise and I can't seem to figure out a way to test this functionality with Rspec. Here is a quick view of me simply trying to test the 'Sign Up' method (which does not work:
describe "New Users" do
describe "signing up" do
it "should create a new user" do
lambda do
post :sign_up, :user => Factory.attributes_for(:user)
response.should be_success
end.should change(User, :count).by(1)
end
end
end
I get the following error:
1) UsersController New Users signing up should create a new user
Failure/Error: post :sign_up, :user => Factory.attributes_for(:user)
ActionController::RoutingError:
No route matches {:user=>{:email=>"test#user.com", :password=>"secret", :password_confirmation=>"secret"}, :controller=>"users", :action=>"sign_up"}
# ./spec/controllers/users_controller_spec.rb:14:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:13:in `block (4 levels) in <top (required)>'
The Devise routes configure my user sign up routes as follows:
new_user_registration GET /users/sign_up(.:format) {:action=>"new", :controller=>"devise/registrations"}
I've been pulling my hair out with this, and can't seem to find any help in this area. Perhaps I'm approaching it wrong, but I want to configure all the aspects of setting up a user's account (ie. their company defaults, profile settings, etc..) on the initial sign up form. First I need to just figure out how to test the sign up process.
Thanks in advance!
First of all the routes you should link to is, because devise are using a POST method for sign-up:
user_registration POST /users(.:format) devise/registrations#create
Maybe you can try pass there syntax such as:
it "should create a new user" do
expect {
post :create, user: FactoryGirl.attributes_for(:user)
response.should be_redirect
}.should change(User, :count).by(1)
end
EDIT
Ok then, I maybe figure out how to solve the route problem, I added a new controller:
UsersController < Devise::RegistrationsController
and also added there method sign_up. Then in routes.rb I added this code:
devise_for :users
devise_scope :user do
post "/sign_up", :to => "devise/registrations#create"
end
and finally this line before the test into the test:
#request.env["devise.mapping"] = Devise.mappings[:user]
But I have there problem with validations, but I think it is for my app because I just made it in new branch on existing system. Hope it could help you. Nevertheless, I think this approach is quite hack or not common. I would rather go with recommended Devise approach. You can always create an user dependencies with FactoryGirl viz this link. Hope it will help you.
BTW Sry for the nonsense post about sign in:) I was tired:)
Isn't it
post :users
The new_user_registration route redirects to the page containing the form (new user action), not the create user action. You should find something like in your routes:
user_registration POST /users {:action => "create", :controller => "devise/registrations"}
Check you rake routes.

how to TDD deleting a user in devise

I setup Devise so I can write controller specs with this.
Then I setup Devise so users cannot delete their accounts.
Now I want to write a spec to make sure the controller is unable to call the destroy action on the Devise user. How do I write this?
In my controller the Devise part looks like this
devise_for :users, skip: :registrations do
resource :registration,
only: [:new, :create, :edit, :update],
path: 'users',
path_names: { new: 'sign_up' },
controller: 'devise/registrations',
as: :user_registration do
get :cancel
end
end
In my spec I'm trying to do the following but it doesn't work. I'm not even sure I'm writing it right. I think the page I'm trying to access is wrong.
describe UsersController do
login_user # from devise controller helper
it "does not allow deleting of user" do
get :users, :method => :delete
# assert here user was not deleted
end
end
I think what you really want to test is whether or not the route exists for the registrations#destroy action. If there is no route, then the action will not be called since it can't be routed to the controller.
For a destroy action, we need to try to route a DELETE action to the users path. so, something like this might do the trick:
{ :delete=> "/users" }.should_not be_routable
Test syntax pulled from a similar answer here:
Rails RSpec Routing: Testing actions in :except do NOT route
Your mixing your http verbs for one thing. You should be doing
delete :destroy, id: #user
Your going to have to get #user from somewhere, I have it set by controller macros personally.
Then you can either check the response header for unsuccessful, or more easily
#user.should exist
I would put the following in my controller spec when testing this kind of thing (although i'd use FactoryGirl to create my test user):
it "does not allow deletion of a user" do
user = User.create!([insert valid args here])
expect {
delete :destroy, id: user
}.not_to change(User, :count)
end

Resources