Question

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 => "another@example.com")
        third  = Factory(:user, :name => "Ben", :email => "another@example.net")
        #@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 => "user@example.com",
                      :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 => "user@example.org",
                      :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 => "user@example.net")
            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 => "admin@example.com", :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 => "user@example.com",
      :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[user@foo.com THE_USER@foo.bar.org first.last@foo.jp]
    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("bar@foo.com", @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 => "user@example.com",
      :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!

Was it helpful?

Solution

I have just recently come across this same issue and resolved it by removing the bang (!) from the create method call:

@user = User.create(@attr)

HTH

OTHER TIPS

Your user_spec.rb does not match with the one from Listing 10.34 in the tutorial. More specifically, the before(:each) block.

your user_spec.rb:

before(:each) do
    @user = User.create!({
    :name => "Example User",
    :email => "user@example.com",
    :password => "foobar",
    :password_confirmation => "foobar"
    })#(@attr)
end

Listing 10.34:

before(:each) do
    @user = User.create!(@attr)
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top