I'm now making Rspec test for users_controller.rb. However I'm in trouble the error NoMethodError: undefined method 'user_url' as follow.
FF
Failures:
1) UsersController PUT update user update does not succeed
Failure/Error: put :update, {:id => user.to_param}, valid_session, :user_route => user
NoMethodError:
undefined method `user_url' for #<UsersController:0x52e40e0>
# ./app/controllers/users_controller.rb:21:in `block (2 levels) in update'
# ./app/controllers/users_controller.rb:18:in `update'
# ./spec/controllers/users_controller_spec.rb:64:in `block (3 levels) in <top (required)>'
2) UsersController PUT update user update succeeds
Failure/Error: put :update, {:id => user.to_param}, valid_session, :user_route => user
NoMethodError:
undefined method `user_url' for #<UsersController:0x53bc560>
# ./app/controllers/users_controller.rb:21:in `block (2 levels) in update'
# ./app/controllers/users_controller.rb:18:in `update'
# ./spec/controllers/users_controller_spec.rb:58:in `block (3 levels) in <top (required)>'
Finished in 0.679 seconds
2 examples, 2 failures
Failed examples:
rspec ./spec/controllers/users_controller_spec.rb:61 # UsersController PUT update user update does not succeed
rspec ./spec/controllers/users_controller_spec.rb:56 # UsersController PUT update user update succeeds
Randomized with seed 33412
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "user#edit" }
format.json { render json: #idea.errors, status: :unprocessable_entity }
end
end
end
end
Also here is my Rspec users_controller_spec.rb. I made two tests about "POST update". One is for being updated successfully. Another is for not being updated. (About the latter, I put the stub User.stub(:update_attribute).and_return(false) which I expect that "update_attribute" returns "false" so that process proceeds to "else".)
require 'spec_helper'
describe UsersController do
let(:valid_attributes) { {
"email" => "hoge#hogehoge.com",
"password" => "12345678"
} }
def valid_session
{}
end
describe "PUT update" do
it "user update succeeds" do
user = User.create! valid_attributes
put :update, {:id => user.to_param}, valid_session
assigns(:user).should eq(user)
end
it "user update does not succeed" do
user = User.create! valid_attributes
User.stub(:update_attribute).and_return(false)
put :update, {:id => user.to_param}, valid_session
assigns(:user).should eq(user)
response.should render_template("edit")
end
end
end
I have no idea to solve this, because I cannot understand where user_url did come. So I would like to have your help.
When you use redirect_to #user, rails sends that request to UsersController#show, but it does so by calling user_url(#user). If I had to guess, you probably don't have the line that defines user_url:
resources :users
in your routes.rb file. This would automatically create the named route user_url that your controller is referencing with redirect_to #user
Alternatively, you could define the route yourself in your routes.rb file like so:
get "/users/show" => "users#show", as: :user
But that's not really the 'Rails-y' way to do it. At any time, you can run the command rake routes in the terminal to see all the named routes you have defined in your routes.rb file. If user isn't there, then you need to define it like I mentioned above.
More info on named routes here: http://guides.rubyonrails.org/routing.html#singular-resources
If you are using devise then check if the following method returns anything.
def after_sign_in_path_for(resource)
in application_controller.rb
If the method returns nothing you will receive the error:
undefined method `user_url' for #
I also ended up removing
stored_location_for(resource)
in after_sign_in_path_for(resource) because it was causing an endless loop. Refer to this answer for details.
rails:3 Devise signup Filter chain halted as :require_no_authentication rendered or redirected
Related
I am new to Rspec and I am following a tutorial, I ran the following commands on a new rails project:
bundle exec rails generate scaffold Person first_name:string last_name:string
bundle exec rake db:migrate db:test:prepare
bundle exec rspec
And I get 15 failures, some of them shown below:
1) PeopleController POST create with valid params redirects to the created person
Failure/Error: response.should redirect_to(Person.last)
NoMethodError:
undefined method `assertions' for #<RSpec::Rails::TestUnitAssertionAdapter::AssertionDelegator:0x007fe7b2417980>
# ./spec/controllers/people_controller_spec.rb:80:in `block (4 levels) in <top (required)>'
2) PeopleController POST create with invalid params assigns a newly created but unsaved person as #person
Failure/Error: post :create, {:person => { "first_name" => "invalid value" }}, valid_session
ArgumentError:
wrong number of arguments (1 for 2+)
# ./app/controllers/people_controller.rb:30:in `block in create'
# ./app/controllers/people_controller.rb:29:in `create'
# ./spec/controllers/people_controller_spec.rb:88:in `block (4 levels) in <top (required)>'
3) PeopleController POST create with invalid params re-renders the 'new' template
Failure/Error: post :create, {:person => { "first_name" => "invalid value" }}, valid_session
ArgumentError:
wrong number of arguments (1 for 2+)
# ./app/controllers/people_controller.rb:30:in `block in create'
# ./app/controllers/people_controller.rb:29:in `create'
# ./spec/controllers/people_controller_spec.rb:95:in `block (4 levels) in <top (required)>'
4) PeopleController DELETE destroy redirects to the people list
Failure/Error: response.should redirect_to(people_url)
NoMethodError:
undefined method `assertions' for #<RSpec::Rails::TestUnitAssertionAdapter::AssertionDelegator:0x007fe7b41b9510>
# ./spec/controllers/people_controller_spec.rb:156:in `block (3 levels) in <top (required)>'
5) PeopleController PUT update with valid params redirects to the person
Failure/Error: response.should redirect_to(person)
NoMethodError:
undefined method `assertions' for #<RSpec::Rails::TestUnitAssertionAdapter::AssertionDelegator:0x007fe7b3a4c188>
# ./spec/controllers/people_controller_spec.rb:122:in `block (4 levels) in <top (required)>'
...........
Here is the people controller its referring to
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render :show, status: :created, location: #person }
else
format.html { render :new }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { render :show, status: :ok, location: #person }
else
format.html { render :edit }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url, notice: 'Person was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:first_name, :last_name)
end
end
Why is a scaffold generated code failing these rspec tests?
Are you also using minitest? Try changing the version in your gemfile to e.g.:
gem 'minitest', '~> 4.0'
I run an RSpec testcase that fills a form and submits it. I get the following error:
1) Sign Up Advertiser after adding valid information should create a user
Failure/Error: expect { click_button submit }.to change(User, :user_key)
NoMethodError:
undefined method `model_name' for Fixnum:Class
# /mnt/hgfs/Projekte/adserve.example.de/app/controllers/advertisers_controller.rb:31:in `tryToCreateUser'
# /mnt/hgfs/Projekte/adserve.example.de/app/controllers/advertisers_controller.rb:14:in `create'
# ./sign_up_advertiser_spec.rb:32:in `block (4 levels) in <top (required)>'
# ./sign_up_advertiser_spec.rb:32:in `block (3 levels) in <top (required)>'
This is the code for the controller:
class AdvertisersController < ApplicationController
...
def home
#menuindex = 0
end
def create
#user = Advertiser.new (params[:advertiser])
tryToCreateUser
end
def tryToCreateUser
if #user.save
#user = Advertiser.retrieve(#user.id)
redirect_to home, :notice => "You successfully signed up " + #user.full_name
else
render :action => "/users/new", :layout => 'application'
end
end
end
And this is what the routes.rb looks like
match "signup_advertiser" => "advertisers#new", :as => "signup_advertiser"
match "signup_publisher" => "publishers#new", :as => "signup_publisher"
get "advertisers_home" => "advertisers#home"
resources :advertisers
So I guess the mistake is in the redirect_to part. But I can't figure it out. I fiddled around with rendering a custom action in 'home' and some other stuff. I think it's something pretty basic so help would be very appreciated. Thanks.
Yes, the problem is there. You should use home as a symbol on the redirect_to method:
def tryToCreateUser
if #user.save
#user = Advertiser.retrieve(#user.id)
redirect_to :home, :notice => "You successfully signed up " + #user.full_name
else
render :action => "/users/new", :layout => 'application'
end
end
What you do now is: redirect_to 0 since you are actually calling the controllers method "home".
This is my RSpec test:
describe "GET #show" do
it "assigns the requested user to #user" do
user = FactoryGirl.build(:user)
get :show, id: user
assigns(:user).should eq(user)
end
end
This is my rails controller:
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
I get the following error message:
Failures:
1) UsersController GET #show assigns the requested user to #user
Failure/Error: get :show, id: user
ActiveRecord::RecordNotFound:
Couldn't find User without an ID
# /home/tim/fairym/app/controllers/users_controller.rb:25:in `show'
# ./users_controller_spec.rb:21:in `block (3 levels) in <top (required)>'
What is the proper way to use the get method here in order to make the test pass?
You should use FactoryGirl.create and not build. The reason is that create actually makes an entry in the database, including ID. build only makes an object in the memory, without an ID.
In my controller I have:
class UsersController < ApplicationController
load_and_authorize_resource
def create
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
end
But I get undefined method 'save' for nil:NilClass
Failures:
1) UsersController if the user passes all the authorizations POST #create should create a new User with some parameters
Failure/Error: post :create, :user => { :email => 'puppa#puppa.pup' }
NoMethodError:
undefined method `save' for nil:NilClass
# ./app/controllers/users_controller.rb:47:in `block in create'
# ./app/controllers/users_controller.rb:46:in `create'
# ./spec/controllers/users_controller_spec.rb:66:in `block (4 levels) in <top (required)>'
Finished in 0.10714 seconds
1 example, 1 failure
I was expecting load_resources to populate #user = User.new(params[:user])
I was looking at CanCan internals following the entire flow and I discovered that in controller_resource.rb when we reach #build_resource we have:
def build_resource
resource = resource_base.new(resource_params || {})
assign_attributes(resource)
end
But resource here is nil... it's normal? what I'm missing? It's related with my problem with create action?
EDIT
here is my ability.rb
class Ability
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
# check if the user is registered or a guest user (not logged in)
if user.present?
if user.any_role? :super_admin
can :manage, :all
end
if user.any_role? :admin
can :manage, [User, Institution, Project, Order]
end
if user.any_role? :user
can :show, Project
can [:add, :change], :cart
can [:create, :show], Order, :user_id => user.id
can :download, UrlConnector
end
end
end
end
EDIT 2
While calling POST create I have:
in RSpec environment:
resource_base: User
resource_class: User
#params: {"user"=>{"email"=>"puppa#puppa.pup"}, "controller"=>"users", "action"=>"create"}
in browser as superadmin or admin, it's the same:
resource_base: User
resource_class: User
#params: {"utf8"=>"✓", "authenticity_token"=>"95qQ4H/+CLU96jCIO6U/YtgIQ5zWxE7pg0BedVMPSGk=", "user"=>{"email"=>"estanost#alumnes.ub.edu", "password"=>"264763", "password_confirmation"=>"264763", "ragionesociale"=>"fff", "partitaiva"=>"12345678901", "address"=>"via plutarco, 36", "city"=>"Manduria", "cap"=>"74024", "phone"=>"099979456", "role_ids"=>["3"]}, "commit"=>"Create User", "action"=>"create", "controller"=>"users"}
Try placing cancan as the last gem in the Gemfile
I think you should get rid of the if user.present? block, add user ||= User.new where that if block starts. This way, you will always have a user object. Of course, it won't pass any of your cancans, so the rest should fall through gracefully.
I'm working on the exercises from Chapter 10 of the Rails Tutorial and ran in to a snag with the exercise that has me ensure that an admin user can't delete themselves. My initial idea was to simply check the id of the current user and compare it against params[:id] to make sure that they're not equal. My destroy action in my Users controller looked like this:
def destroy
if current_user.id == params[:id].to_i
flash[:notice] = "You cannot delete yourself."
else
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
end
redirect_to users_path
end
This works perfectly when I test it manually in the app but 3 of my RSpec tests fail with the same "undefined method 'to_i'" error (as seen below):
1) UsersController DELETE 'destroy' as an admin user should destory the user
Failure/Error: delete :destroy, :id => #user
NoMethodError:
undefined method `to_i' for #<User:0x000001032de188>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:310:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:309:in `block (4 levels) in <top (required)>'
2) UsersController DELETE 'destroy' as an admin user should redirect to the users page
Failure/Error: delete :destroy, :id => #user
NoMethodError:
undefined method `to_i' for #<User:0x000001032b5850>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:315:in `block (4 levels) in <top (required)>'
3) UsersController DELETE 'destroy' as an admin user should not allow you to destroy self
Failure/Error: delete :destroy, :id => #admin
NoMethodError:
undefined method `to_i' for #<User:0x0000010327e350>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:321:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:320:in `block (4 levels) in <top (required)>'
If I use the params[:id] to find the user and compare it to the current_user like I have below then it works both in the app and in RSpec.
def destroy
if current_user == User.find(params[:id])
flash[:notice] = "You cannot delete yourself."
else
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
end
redirect_to users_path
end
Why would there be a problem in RSpec with the "to_i" method? If anyone is wondering I was leaning toward that approach because I thought it would best to simply compare the current user id to the id of the user targeted for deletion (via the params[:id]) instead of hitting the db to "find" the user.
For reference this is my RSpec test:
describe "DELETE 'destroy'" do
before(:each) do
#user = Factory(:user)
end
...
describe "as an admin user" do
before(:each) do
#admin = Factory(:user, :email => "admin#example.com", :admin => true)
test_sign_in(#admin)
end
it "should destory the user" do
lambda do
delete :destroy, :id => #user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => #user
response.should redirect_to(users_path)
end
it "should not allow you to destroy self" do
lambda do
delete :destroy, :id => #admin
end.should change(User, :count).by(0)
response.should redirect_to(users_path)
flash[:notice].should =~ /cannot delete yourself/
end
end
end
Any help would be appreciated!
In your specs, try using #user.id instead of #user on your :id parameter (I realize the Tutorial says to just use #user, but something may be going on where the id isn't being properly extracted):
delete :destroy, :id => #user.id
But you may consider restructuring to something like this:
#user = User.find(params[:id])
if current_user == #user
flash[:notice] = "You cannot delete yourself."
else
#user.destroy
flash[:success] = "User destroyed."
end