How to test extended functionality after devise sign_up action? - ruby-on-rails

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.

Related

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

RailsTutorial: what's the difference between signup_path and user_path?

I'm in chapter 7 of Michael Hartl's Rails Tutorial and I'm having a hard time understanding the "_path"s that he calls on for a particular test (section 7.3.4 to be exact). Here's the code in question:
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, user: { name: "",
email: "user#invalid",
password: "foo",
password_confirmation: "bar" }
end
assert_template 'users/new'
end
end
In particular, I'm confused about get signup_path and post users_path. When I go back and search the book for signup_path, Table 5.1 indicates it is the named route for [sample_app url]/signup which should direct visitors to the signup page of the website. Additionally, when I search the book for users_path, Table 7.1 indicates that it is the named route for [sample_app url]/users using the 'create' controller action because we are issuing a POST HTTP request.
NOTE: In responses, please don't suggest altering this code. This is based on Hartl's Rails Tutorial and the assumption is that the code is correct and should work as is. Please make sure your answers explain the code I've posted (or other code from his tutorial) and not modifications to the existing code.
EDIT: OK, so I think I can see the difference between signup_path and users_path: in the routes.rb file, /signup routes to users#new, which means it is routed to the users controller and specifically the 'new' method of that controller. I know the result of this is loading the new.html.erb file. Part of what I don't get is -- how does the users#new controller action know which HTML page to load? Does the 'new' method automatically call whichever view is also called 'new'? OR... (Here's the relevant controller code for the new method:
def new
#user = User.new
end
The other part of my problem is with users_path: rake routes says the POST method for /users is routes through the users#create controller/action. But my routes.rb file doesn't have a route to reflect this:
Rails.application.routes.draw do
root 'static_pages#home'
get '/help' => 'static_pages#help'
get '/about' => 'static_pages#about'
get '/contact' => 'static_pages#contact'
get '/signup' => 'users#new'
resources :users
end
So the second part of the question is: How does the routes file know to route the post users_path to the users#create controller/action?
The dont point to the same page, GET signup_path will GET you to the page where user can sign up while POST users_path is a different route where you send parameters that you have generate on GET signup_path.
Also you dont need to search tables to see to what URL each _path points, just type
rake routes
in command prompt and you will see what each path is.
This small line
resources :users
is actually a shortcut for seven different (but very common) routes that cover all CRUD (create, read, update, and delete) operations on a resource. One of them is exactly:
users_path POST /users users#create create a new user

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

How to deal with RoutingError while testing with Rspec?

I created a controller called PolicyController and nested its route like this:
scope "/your"
resources :shops do
resources :policies
end
end
Now when I'm trying to test this controller I keep getting this error:
1) PoliciesController POST 'create' should be successful
Failure/Error: post 'create'
ActionController::RoutingError:
No route matches {:controller=>"policies", :action=>"create"}
# ./spec/controllers/policies_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
Not sure how to set it right. Would appreciate the help.
Edit: Forgot my specs:
describe PoliciesController do
describe "POST 'create'" do
it "should be successful" do
post 'create'
response.should be_success
end
end
Do you think this will work?
post :create, :shop_id => 1
Definitely want to create a new shop in a before block.

Rspec 2.3 on Rails 3.0.3 giving some controller access problems?

It seems a bunch of my Rspec tests now fail after moving my application to Rspec 2.3 and Rails 3.0.3
An example is here:
it "should not be able to access 'destroy'" do
delete :destroy
response.should redirect_to(signin_path)
flash[:error].should == "You must be signed in to view this page."
end
will give me the error:
1) FriendshipsController when not logged in: should not be able to access 'destroy'
Failure/Error: delete :destroy
No route matches {:controller=>"friendships", :action=>"destroy"}
# ./spec/controllers/friendships_controller_spec.rb:21:in `block (3 levels) in <top (required)>'
In my routes.rb file, I've mapped the resources for this controller...
resources :friendships
Same for
get :edit
get :show
put :update
Only one that seems to work is
post :create
But this I cannot confirm 100%.
Any thoughts? Thanks for your time!
UPDATE:
get :new
also works and my UserSessions controller (Authlogic) doesn't seem to suffer from this problem. Nothing I've done different in my UserSessions controller, model, or test that I can tell.
In the spec, try calling the method by:
delete :destroy, :id => "1"

Resources