Rails by Example(作者Michael Hartl),第9课,登录测试不会通过

时间:2011-09-30 09:33:18

标签: ruby-on-rails

我正在按照第9课进行登录,但登录测试不会通过!我按照代码写了字母,它仍然没有通过。

使用浏览器进行测试时 - 登录无误地运行..

故障:

1)SessionsController使用有效的电子邮件和密码POST'create'应该签署用户      失败/错误:controller.current_user.should == @user        预期:#             得到:零(使用==)      './spec/controllers/sessions_controller_spec.rb:55:在'

中的块(4级)

2)SessionsController POST'create'使用有效的电子邮件和密码应重定向到用户显示页面      失败/错误:response.should redirect_to(user_path(@user))        预期块返回真值。      #./spec/controllers/sessions_controller_spec.rb:61:in'块(4级)in'

在5.12秒内完成 7个例子,2个失败

失败的例子:

rspec ./spec/controllers/sessions_controller_spec.rb:53 # SessionsController POST 'create' with valid email and password should sign the user in
rspec ./spec/controllers/sessions_controller_spec.rb:59 # SessionsController POST 'create' with valid email and password should redirect to the user show page

正如您所看到的,测试controller.current_user.should == @user由于某种原因返回nil。

请帮我理解这个..

谢谢

SessionHelper

    module SessionsHelper

 def sign_in(user)
    cookies.permanent.signed[:remember_token] = [user.id, user.salt]
    self.current_user= user
     end


def signed_in?
    !self.current_user.nil?
end
def current_user=(user)
    @current_user = user
end

 def current_user
    @current_user ||= user_from_remember_token
end

  private

def user_from_remember_token
  User.authenticate_with_salt(*remember_token)
end

def remember_token
  cookies.signed[:remember_token] || [nil, nil]
end
   end

会话控制器

    class SessionsController < ApplicationController
     def new
       @title = "Sign In"
       end

    def create
    user = User.authenticate(params[:session][:email], params[:session][:password])
    if user.nil?
        flash.now[:error] = "Invalid email/password"

        @title = "Sign In (right this time)"
        render 'new'
    else
        #sign in the user
        sign_in @user
        redirect_to user

    end
end

def destroy

end
   end

用户模型

   require 'digest'
    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 => {:minimum => 2, :maximum => 50}
validates :email, :presence => true, :format => {:with => email_regex}, :uniqueness => {:case_sensitive => false }

#Automatically creates the virtual password confimration attribute
validates :password, :presence => true,
                                :confirmation => true,
                                :length => {:within => 6..40}


before_save :encrypt_password

def has_password?(submitted_password)
    self.salt = make_salt if new_record?
    encrypted_password == encrypt(submitted_password)
end

def self.authenticate(email, submitted_password)
    user = find_by_email(email)
    return nil if user.nil?
    return nil if user.has_password?(submitted_password)
end

 def self.authenticate_with_salt(id, cookie_salt)
    user = find_by_id(id)
    (user && user.salt == cookie_salt) ? user : nil
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

会话控制器规范

require 'spec_helper'

describe SessionsController do
render_views


  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 In")
    end



  end

  describe "POST 'create'" do

        describe "invalid login" do
            before(:each) do
                @attr = {:email => "email@example.com", :password => "invalid"}
            end

            it "should re-render the new page" do
                post :create, :session => @attr
                response.should render_template('new')
            end

            it "should have the right title" do
                post :create, :session => @attr
                response.should have_selector("title", :content => "Sign In (right this time)")
            end

            it "should have flash.now message" do
                post :create, :session => @attr
                flash.now[:error].should =~ /invalid/i
            end
        end

        describe "success" do

            before(:each) do
                @user = Factory(:user)
                @attr = { :email => @user.email, :password => @user.password }
            end

            it "should sign the user in" do
                post :create, :session => @attr
                controller.current_user.should == @user
                controller.should be_signed_in
            end

            it "should redirect to the user show page" do
                post :create, :session => @attr
                response.should redirect_to(user_path(@user))
            end
        end

    end

end

3 个答案:

答案 0 :(得分:3)

我假设您已经完成了第9.3.3节并将authenticate类方法添加到您的用户模型中。

如果您检查身份验证(9.17)类方法,则它具有user = find_by_email(email)。您应该首先检查您的工厂是否在测试数据库中创建了一个用户。

<强>更新

你在SessionsHelper中有这个吗?

def signed_in?
  !current_user.nil?
end

更新2

在SessionsHelper !!

中删除以下内容
def current_user=(user)
    @current_user = user
end

Hartl非常具体地说明为什么要删除这位作家

  

如果我们这样做,我们将有效地复制其功能   attr_accessor,首先见4.4.5节并用于制作   第7.1.1.7节中的虚拟密码属性问题在于它   完全无法解决我们的问题:使用清单9.15中的代码,   用户的登录状态将被忘记:用户一进入   另一个页面噗! - 会话将结束,用户将会   自动退出。

     

为了避免这个问题,我们可以找到对应的会话用户   清单9.12中的代码创建的cookie,如清单所示   9.16。

取而代之的是

def current_user
  @current_user ||= user_from_remember_token
end
  

首先,代码清单9.16使用了常见但最初模糊的|| =(“或者   等于“)赋值运算符(方框9.4)。它的作用是设置   @current_user实例变量给用户对应的   记住令牌,但仅限于@current_user未定义.8在其他情况下   单词,构造调用user_from_remember_token方法   第一次调用current_user,但是在后续调用中   返回@current_user而不调用user_from_remember_token。

答案 1 :(得分:1)

我有同样的问题。我也明白它应该被替换。但它不应该both methods are needed

def current_user=(user)
  @current_user = user
end

def current_user
  @current_user ||= user_from_remember_token
end 

答案 2 :(得分:0)

让我永远跟踪这个... ...

rspec错误消息:

 1) SessionsController POST 'create' with valid email and password should sign the user in
     Failure/Error: controller.current_user.should == @user
     NoMethodError:
       undefined method `current_user' for #<SessionsController:0x00000005426eb8>
     # ./spec/controllers/sessions_controller_spec.rb:51:in `block (4 levels) in <top (required)>'

您想要修改 app / helpers / sessions_helper.rb

WRONG:

def current_user=(user)
    @current_user = user ||= user_from_remember_token
end

RIGHT:

def current_user
    @current_user ||= user_from_remember_token
end

当我跟随时,我显然没有给予足够的关注,不幸的是,来自rspec的错误信息并不像通常那样有用。希望这有帮助!