I'm a RoR-Learner and I made my way to the RoR-Tutorial by Michael Hartl, but actually I'm facing a problem at Chapter 10.4. I did all the Listings up to 10.42, but 3 of my Rspec-Tests are failing.
It says:
1) Users admin attribute should respond to admin Failure/Error: @user = User.create!(@attr) ActiveRecord::RecordInvalid: Validation failed: Name can't be blank, Email can't be blank, Email is invalid, Password can't be blank, Password is too short (minimum is 6 characters) ./spec/requests/users_spec.rb:52:in `block (3 levels) in
2) Users admin attribute should not be an admin by default Failure/Error: @user = User.create!(@attr) ActiveRecord::RecordInvalid: Validation failed: Name can't be blank, Email can't be blank, Email is invalid, Password can't be blank, Password is too short (minimum is 6 characters) ./spec/requests/users_spec.rb:52:in `block (3 levels) in
3) Users admin attribute should be convertible to an admin Failure/Error: @user = User.create!(@attr) ActiveRecord::RecordInvalid: Validation failed: Name can't be blank, Email can't be blank, Email is invalid, Password can't be blank, Password is too short (minimum is 6 characters) ./spec/requests/users_spec.rb:52:in `block (3 levels) in
I already took a careful look on my users_controllers_spec.rb and my user_spec.rb, but I couldn't find an explanation for the mistakes. Does anyone have an idea?
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]
@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?escape=false&page=2",
:content => "2")
response.should have_selector("a", :href => "/users?escape=false&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
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 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
it "should sign the user in" do
post :create, :user => @attr
controller.should be_signed_in
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
This is my user_spec.rb
require 'spec_helper'
describe User do
before(:each) do
@attr = {
:name => "Example User",
:email => "[email protected]",
:password => "foobar",
:password_confirmation => "foobar"
}
end
it "should create a new instance given valid attributes" do
User.create!(@attr)
end
it "should require a name" do
no_name_user = User.new(@attr.merge(:name => ""))
no_name_user.should_not be_valid
end
it "should require an email address" do
no_email_user = User.new(@attr.merge(:email => ""))
no_email_user.should_not be_valid
end
it "should reject names that are too long" do
long_name = "a" * 51
long_name_user = User.new(@attr.merge(:name => long_name))
long_name_user.should_not be_valid
end
it "should accept valid email addresses" do
addresses = %w[[email protected] [email protected] [email protected]]
addresses.each do |address|
valid_email_user = User.new(@attr.merge(:email => address))
valid_email_user.should be_valid
end
end
it "should reject invalid email addresses" do
addresses = %w[user@foo,com user_at_foo.org example.user@foo.]
addresses.each do |address|
invalid_email_user = User.new(@attr.merge(:email => address))
invalid_email_user.should_not be_valid
end
end
it "should reject duplicate email addresses" do
# Put a user with given email address into the database.
User.create!(@attr)
user_with_duplicate_email = User.new(@attr)
user_with_duplicate_email.should_not be_valid
end
it "should reject email addresses identical up to case" do
upcased_email = @attr[:email].upcase
User.create!(@attr.merge(:email => upcased_email))
user_with_duplicate_email = User.new(@attr)
user_with_duplicate_email.should_not be_valid
end
describe "password validations" do
it "should require a password" do
User.new(@attr.merge(:password => "", :password_confirmation => "")).
should_not be_valid
end
it "should require a matching password confirmation" do
User.new(@attr.merge(:password_confirmation => "invalid")).
should_not be_valid
end
it "should reject short passwords" do
short = "a" * 5
hash = @attr.merge(:password => short, :password_confirmation => short)
User.new(hash).should_not be_valid
end
it "should reject long passwords" do
long = "a" * 41
hash = @attr.merge(:password => long, :password_confirmation => long)
User.new(hash).should_not be_valid
end
end
describe "password encryption" do
before(:each) do
@user = User.create!(@attr)
end
it "should have an encrypted password attribute" do
@user.should respond_to(:encrypted_password)
end
it "should set the encrypted password" do
@user.encrypted_password.should_not be_blank
end
describe "has_password? method" do
it "should be true if the passwords match" do
@user.has_password?(@attr[:password]).should be_true
end
it "should be false if the passwords don't match" do
@user.has_password?("invalid").should be_false
end
end
end
describe "authenticate method" do
it "should return nil on email/password mismatch" do
wrong_password_user = User.authenticate(@attr[:email], "wrongpass")
wrong_password_user.should be_nil
end
it "should return nil for an email address with no user" do
nonexistent_user = User.authenticate("[email protected]", @attr[:password])
nonexistent_user.should be_nil
end
it "should return the user on email/password match" do
matching_user = User.authenticate(@attr[:email], @attr[:password])
matching_user.should == @user
end
end
describe "admin attribute" do
before(:each) do
@user = User.create!({
:name => "Example User",
:email => "[email protected]",
:password => "foobar",
:password_confirmation => "foobar"
})#(@attr)
//EDIT: I tried both, the fill-in by hand an the original code with (@attr) --> nothing changes, still the same mistake
end
it "should respond to admin" do
@user.should respond_to(:admin)
end
it "should not be an admin by default" do
@user.should_not be_admin
end
it "should be convertible to an admin" do
@user.toggle!(:admin)
@user.should be_admin
end
end
end
EDIT: User.rb
== Schema Information
Table name: users
id :integer not null, primary key
name :string(255)
email :string(255)
created_at :datetime
updated_at :datetime
//it's outcommented
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
If some important details are missing, please ask, I'm prepared to update this post (just didn't want to overload it, because the code is already huge enough).
Thanks for your attention!