Reputation: 11
I'm working on the Rails tutorial and as follow the instructions, I always get the results expected but after finishing chapter 10, I get the bellow errors and I can't find what it the issue is.
1) UsersController PUT 'update' authentication of edit/update pages for non-signed-in users should deny access to 'edit'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
2) UsersController PUT 'update' authentication of edit/update pages for non-signed-in users should deny access to 'update'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
3) UsersController PUT 'update' authentication of edit/update pages for signed-in users should require matching users for 'edit'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
4) UsersController PUT 'update' authentication of edit/update pages for signed-in users should require matching users for 'update'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
5) UsersController DELETE 'destroy' as a non-signed-in user should deny access
Failure/Error: delete :destroy, :id => @user
NoMethodError:
undefined method `admin?' for nil:NilClass
# ./app/controllers/users_controller.rb:68:in `admin_user'
# ./spec/controllers/users_controller_spec.rb:303:in `block (4 levels) in <top (required)>'
the app runs well and the functionalities are done but the tests don't pass. Initially I thought there might be typos and then I double checked to see if I missed something but there was not luck...
For reference this is my RSpec test:
describe "PUT 'update'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
describe "failure" do
before(:each) do
@attr = { :email => "", :name => "", :password => "",
:password_confirmation => "" }
end
it "should render the 'edit' page" do
put :update, :id => @user, :user => @attr
response.should render_template('edit')
end
it "should have the right title" do
put :update, :id => @user, :user => @attr
response.should have_selector("title", :content => "Edit user")
end
end
describe "success" do
before(:each) do
@attr = { :name => "New Name", :email => "[email protected]",
:password => "barbaz", :password_confirmation => "barbaz" }
end
it "should change the user's attributes" do
put :update, :id => @user, :user => @attr
@user.reload
@user.name.should == @attr[:name]
@user.email.should == @attr[:email]
end
it "should redirect to the user show page" do
put :update, :id => @user, :user => @attr
response.should redirect_to(user_path(@user))
end
it "should have a flash message" do
put :update, :id => @user, :user => @attr
flash[:success].should =~ /updated/
end
end
describe "authentication of edit/update pages" do
before(:each) do
@user = Factory(:user)
end
describe "for non-signed-in users" do
it "should deny access to 'edit'" do
get :edit, :id => @user
response.should redirect_to(signin_path)
end
it "should deny access to 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(signin_path)
end
end
describe "for signed-in users" do
before(:each) do
wrong_user = Factory(:user, :email => "[email protected]")
test_sign_in(wrong_user)
end
it "should require matching users for 'edit'" do
get :edit, :id => @user
response.should redirect_to(root_path)
end
it "should require matching users for 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(root_path)
end
end
end
end
describe "DELETE 'destroy'" do
before(:each) do
@user = Factory(:user)
end
describe "as a non-signed-in user" do
it "should deny access" do
delete :destroy, :id => @user
response.should redirect_to(signin_path)
end
end
describe "as a non-admin user" do
it "should protect the page" do
test_sign_in(@user)
delete :destroy, :id => @user
response.should redirect_to(root_path)
end
end
describe "as an admin user" do
before(:each) do
admin = Factory(:user, :email => "[email protected]", :admin => true)
test_sign_in(admin)
end
it "should destroy 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
end
end
And my user controller methods:
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
flash[:success] = "Profile updated."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
Here is my factories.rb
# By using the symbol ':user', we get Factory Girl to simulate the User model.
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "[email protected]"
user.password "foobar"
user.password_confirmation "foobar"
end
Factory.sequence :name do |n|
"Person #{n}"
end
Factory.sequence :email do |n|
"person-#{n}@example.com"
end
Any help would be GREATLY appreciated!!
Upvotes: 1
Views: 1320
Reputation: 676
I got the same error, because I forgot to prepare the test database:
rake db:test:prepare
Upvotes: 2
Reputation: 47971
As far as I can see your tables are not being cleared after the tests are run. Are you sure your tests clear the table at exit? Usually the Database Cleaner gem is used to do this.
The problem appears to be with this line of code:
@user = Factory(:user)
in this part of your spec:
describe "authentication of edit/update pages" do
before(:each) do
@user = Factory(:user)
end
Try changing it to
@user = Factory(:user, :email => "[email protected]")
Or remove it completely.
It seems to me that it's nested under this parent spec:
describe "PUT 'update'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
And as here a user model with the same email is created before running the "authentication of edit/update pages"
specs, when in "authentication of edit/update pages"
you create the user the spec fails because email
should be unique.
UPDATE:
I had a look at your spec and looks like you had forgotten to close a block in the right place (and end
keyword was misplaced).
This is the correct spec:
require 'spec_helper'
describe UsersController do
render_views
describe "GET 'index'" do
describe "for non-signed-in users" do
it "should deny access" do
get :index
response.should redirect_to(signin_path)
flash[:notice].should =~ /sign in/i
end
end
describe "for signed-in users" do
before(:each) do
@user = test_sign_in(Factory(:user))
second = Factory(:user, :name => "Bob", :email => "[email protected]")
third = Factory(:user, :name => "Ben", :email => "[email protected]")
@users = [@user, second, third]
30.times do
@users << Factory(:user, :name => Factory.next(:name),
:email => Factory.next(:email))
end
end
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector("title", :content => "All users")
end
it "should have an element for each user" do
get :index
@users[0..2].each do |user|
response.should have_selector("li", :content => user.name)
end
end
it "should paginate users" do
get :index
response.should have_selector("div.pagination")
response.should have_selector("span.disabled", :content => "Previous")
response.should have_selector("a", :href => "/users?page=2",
:content => "2")
response.should have_selector("a", :href => "/users?page=2",
:content => "Next")
end
end
end
describe "GET 'show'" do
before(:each) do
@user = Factory(:user)
end
it "should be successful" do
get :show, :id => @user
response.should be_success
end
it "should find the right user" do
get :show, :id => @user
assigns(:user).should == @user
end
it "should have the right title" do
get :show, :id => @user
response.should have_selector("title", :content => @user.name)
end
it "should include the user's name" do
get :show, :id => @user
response.should have_selector("h1", :content => @user.name)
end
it "should have a profile image" do
get :show, :id => @user
response.should have_selector("h1>img", :class => "gravatar")
end
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the right title" do
get 'new'
response.should have_selector("title", :content => "Sign up")
end
it "should have a name field" do
get :new
response.should have_selector("input[name='user[name]'][type='text']")
end
it "should have an email field" do
get :new
response.should have_selector("input[name='user[email]'][type='text']")
end
it "should have a password field" do
get :new
response.should have_selector("input[name='user[password]'][type='password']")
end
it "should have a password confirmation field" do
get :new
response.should have_selector("input[name='user[password_confirmation]'][type='password']")
end
end
describe "POST 'create'" do
describe "failure" do
before(:each) do
@attr = {:name => "", :email => "", :password => "",
:password_confirmation => ""}
end
it "should not create a user" do
lambda do
post :create, :user => @attr
end.should_not change(User, :count)
end
it "should have the right title" do
post :create, :user => @attr
response.should have_selector("title", :content => "Sign up")
end
it "should render the 'new' page" do
post :create, :user => @attr
response.should render_template('new')
end
end
describe "success" do
before(:each) do
@attr = {:name => "New User", :email => "[email protected]",
:password => "foobar", :password_confirmation => "foobar"}
end
it "should create a user" do
lambda do
post :create, :user => @attr
end.should change(User, :count).by(1)
end
it "should sign the user in" do
post :create, :user => @attr
controller.should be_signed_in
end
it "should redirect to the user show page" do
post :create, :user => @attr
response.should redirect_to(user_path(assigns(:user)))
end
it "should have a welcome message" do
post :create, :user => @attr
flash[:success].should =~ /welcome to the sample app/i
end
end
end
describe "GET 'edit'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
it "should be successful" do
get :edit, :id => @user
response.should be_success
end
it "should have the right title" do
get :edit, :id => @user
response.should have_selector("title", :content => "Edit user")
end
it "should have a link to change the Gravatar" do
get :edit, :id => @user
gravatar_url = "http://gravatar.com/emails"
response.should have_selector("a", :href => gravatar_url,
:content => "change")
end
end
describe "PUT 'update'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
describe "failure" do
before(:each) do
@attr = {:email => "", :name => "", :password => "",
:password_confirmation => ""}
end
it "should render the 'edit' page" do
put :update, :id => @user, :user => @attr
response.should render_template('edit')
end
it "should have the right title" do
put :update, :id => @user, :user => @attr
response.should have_selector("title", :content => "Edit user")
end
end
describe "success" do
before(:each) do
@attr = {:name => "New Name", :email => "[email protected]",
:password => "barbaz", :password_confirmation => "barbaz"}
end
it "should change the user's attributes" do
put :update, :id => @user, :user => @attr
@user.reload
@user.name.should == @attr[:name]
@user.email.should == @attr[:email]
end
it "should redirect to the user show page" do
put :update, :id => @user, :user => @attr
response.should redirect_to(user_path(@user))
end
it "should have a flash message" do
put :update, :id => @user, :user => @attr
flash[:success].should =~ /updated/
end
end
end
describe "authentication of edit/update pages" do
before(:each) do
@user = Factory(:user)
end
describe "for non-signed-in users" do
it "should deny access to 'edit'" do
get :edit, :id => @user
response.should redirect_to(signin_path)
end
it "should deny access to 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(signin_path)
end
end
describe "for signed-in users" do
before(:each) do
wrong_user = Factory(:user, :email => "[email protected]")
test_sign_in(wrong_user)
end
it "should require matching users for 'edit'" do
get :edit, :id => @user
response.should redirect_to(root_path)
end
it "should require matching users for 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(root_path)
end
end
end
describe "DELETE 'destroy'" do
before(:each) do
@user = Factory(:user)
end
describe "as a non-signed-in user" do
it "should deny access" do
delete :destroy, :id => @user
response.should redirect_to(signin_path)
end
end
describe "as a non-admin user" do
it "should protect the page" do
test_sign_in(@user)
delete :destroy, :id => @user
response.should redirect_to(root_path)
end
end
describe "as an admin user" do
before(:each) do
admin = Factory(:user, :email => "[email protected]", :admin => true)
test_sign_in(admin)
end
it "should destroy 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
end
end
end
However in this corrected spec, the UsersController DELETE 'destroy' as a non-signed-in user should deny access
spec fails, because the implementation is incorrect (it assumes current_user
will never return nil
but it sometimes does).
UPDATE 2: All the changes that are necessary to make all the tests pass can be seen here.
Other than indentation fixes the only thing that needed to be fixed was the admin_user
callback in the UsersController
class:
def admin_user
redirect_to(root_path) unless (current_user && current_user.admin?)
end
Upvotes: 2
Reputation: 947
In Listing 10.36, did you paste the entire block of code to create the admin user in, without removing the original block? I had a similar problem at that point in the tutorial and that was the culprit.
Should look like this:
lib/tasks/sample_data.rake
namespace :db do
desc "Fill database with sample data"
task :populate => :environment do
Rake::Task['db:reset'].invoke
admin = User.create!(:name => "Example User",
:email => "[email protected]",
:password => "foobar",
:password_confirmation => "foobar")
admin.toggle!(:admin)
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}@railstutorial.org"
password = "password"
User.create!(:name => name,
:email => email,
:password => password,
:password_confirmation => password)
end
end
end
Upvotes: 0