RoR v3.2教程 - 坚持第9.2.2章

时间:2012-02-19 23:45:55

标签: ruby-on-rails

在这里输入代码我正在努力完成Michael Hartl的Ruby on Rails v3.2教程,我坚持Chapter 9.2.2

以下是我得到的失败消息,即使在完成本节后我的所有测试都应该通过:

sample_app mikael$ bundle exec rspec spec/
.................................................................F..

Failures:

  1) User pages edit with valid information 
     Failure/Error: it { should have_link('Sign out', :href => signout_path) }
       expected link "Sign out" to return something
     # ./spec/requests/user_pages_spec.rb:91:in `block (4 levels) in <top (required)>'

Finished in 2.42 seconds
68 examples, 1 failure

Failed examples:

rspec ./spec/requests/user_pages_spec.rb:91 # User pages edit with valid information 

问题是,在登录用户成功更新其配置文件后,它们会自动注销,导致使用有效信息测试的编辑失败,因为更新后用户应保持登录状态并且“注销”链接应该存在。

我已经梳理了这个寻找我的错误,或者我没有正确地按照教程但找不到解决方案。

在完成第9.2.2节之后,我能够完成所有测试。

以下是我在第9章中更新的文件(包括第9.2.2节和前面所有部分):

规格/请求/ authentication_pages_spec.rb

require 'spec_helper'

describe "Authentication" do

  subject { page }

  describe "signin page" do
    before { visit signin_path }

    it { should have_selector('h1',    text: 'Sign in') }
    it { should have_selector('title', text: 'Sign in') }

  end

  describe "signin" do
    before { visit signin_path }

    describe "with invalid information" do
    before { click_button "Sign in" }

    it { should have_selector('title', text: 'Sign in') }
    it { should have_selector('div.flash.error', text: 'Invalid') }

      describe "after visiting another page" do
        before { click_link "Home" }
        it { should_not have_selector('div.flash.error') }
      end
    end

    describe "with valid information" do
      let(:user) { FactoryGirl.create(:user) }
      before do
        fill_in "Email",    with: user.email
        fill_in "Password", with: user.password
        click_button "Sign in"
      end

      it { should have_selector('title', text: user.name) }
      it { should have_link('Profile', href: user_path(user)) }
      it { should have_link('Settings', href: edit_user_path(user)) }
      it { should have_link('Sign out', href: signout_path) }
      it { should_not have_link('Sign in', href: signin_path) }

      describe "followed by signout" do
        before { click_link "Sign out" }
        it { should have_link('Sign in') }
      end
    end
  end

  describe "authorization" do

    describe "for non-signed-in users" do
      let(:user) { Factory(:user) }

      describe "in the Users controller" do

        describe "visiting the edit page" do
          before { visit edit_user_path(user) }
          it { should have_selector('title', text: 'Sign in') }
        end

        describe "submitting to the update action" do
          before { put user_path(user) }
          specify { response.should redirect_to(signin_path) }
        end
      end
    end

    describe "as wrong user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
      before { sign_in user }

      describe "visiting Users#edit page" do
        before { visit edit_user_path(wrong_user) }
        it { should have_selector('title', text: 'Home') }
      end

      describe "submitting a PUT request to the Users#update action" do
        before { put user_path(wrong_user) }
        specify { response.should redirect_to(root_path) }
      end
    end
  end
end

规格/请求/ user_pages_spec.rb

require 'spec_helper'

describe "User pages" do

  subject { page }

  describe "profile page" do
    let(:user) { FactoryGirl.create(:user) }
    before { visit user_path(user) }

    it { should have_selector('h1',    text: user.name) }
    it { should have_selector('title', text: user.name) }
  end

  describe "signup" do

    before { visit signup_path }

    describe "with invalid information" do
      it "should not create a user" do
        expect { click_button "Sign up" }.not_to change(User, :count)
        end
      end

    describe "error messages" do
      before { click_button "Sign up" }

       let(:error) { 'errors prohibited this user from being saved' }

       it { should have_selector('title', text: 'Sign up') }
       it { should have_content(error) }
    end

    describe "with valid information" do
      before do
        fill_in "Name",         with: "Example User"
        fill_in "Email",        with: "user@example.com"
        fill_in "Password",     with: "foobar"
        fill_in "Confirmation", with: "foobar"
      end

      describe "after saving the user" do
        before { click_button "Sign up" }
        let(:user) { User.find_by_email('user@example.com') }

        it { should have_selector('title', text: user.name) }
        it { should have_selector('div.flash.success', text: 'Welcome') }
        it { should have_link('Sign out') }
      end

    it "should create a user" do
        expect { click_button "Sign up" }.to change(User, :count).by(1)
      end
    end  
  end

  describe "edit" do
    let(:user) { FactoryGirl.create(:user) }
    before do
          sign_in user
          visit edit_user_path(user)
        end

    describe "page" do
      it { should have_selector('h1',    text: "Edit user") }
      it { should have_selector('title', text: "Edit user") }
      it { should have_link('change', href: 'http://gravatar.com/emails') }
    end

    describe "with invalid information" do
      let(:error) { '1 error prohibited this user from being saved' }
      before { click_button "Update" }

      it { should have_content(error) }
    end

    describe "with valid information" do
      let(:user)      { FactoryGirl.create(:user) }
      let(:new_name)  { "New Name" }
      let(:new_email) { "new@example.com" }
      before do
        fill_in "Name",         with: new_name
        fill_in "Email",        with: new_email
        fill_in "Password",     with: user.password
        fill_in "Confirmation", with: user.password
        click_button "Update"
      end

      it { should have_selector('title', text: new_name) }
      it { should have_selector('div.flash.success') }
      it { should have_link('Sign out', :href => signout_path) }
      specify { user.reload.name.should  == new_name }
      specify { user.reload.email.should == new_email }
    end
  end
end

应用/控制器/ users_controller.rb

class UsersController < ApplicationController
  before_filter :signed_in_user, only: [:edit, :update]
  before_filter :correct_user,   only: [:edit, :update]

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
    if @user.save
      sign_in @user
      flash[:success] = "Welcome to MK Rails!"
      redirect_to @user
    else
      render 'new'
    end
  end

  def edit
  end

  def update
    if @user.update_attributes(params[:user])
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

      def signed_in_user
        redirect_to signin_path, notice: "Please sign in." unless signed_in?
      end

      def correct_user
        @user = User.find(params[:id])
        redirect_to(root_path) unless current_user?(@user)
      end
end

应用/助手/ sessions_helper.rb

module SessionsHelper

  def sign_in(user)
    cookies.permanent[:remember_token] = user.remember_token
    current_user = user
  end

  def signed_in?
    !current_user.nil?
  end

  def current_user=(user)
    @current_user = user
  end

  def current_user
    @current_user ||= user_from_remember_token
  end

  def current_user?(user)
    user == current_user
  end

  def sign_out
    cookies.delete(:remember_token)
  end

  private

    def user_from_remember_token
      remember_token = cookies[:remember_token]
      User.find_by_remember_token(remember_token) unless remember_token.nil?
    end
end

规格/支持/ utilities.rb

def full_title(page_title)
  base_title = "MK Rails"
  if page_title.empty?
    base_title
  else
    "#{base_title} | #{page_title}"
  end
end

def valid_signin(user)
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign in"
end

RSpec::Matchers.define :have_error_message do |message|
  match do |page|
    page.should have_selector('div.flash.error', text: message)
  end
end

def sign_in(user)
  visit signin_path
  fill_in "Email",    with: user.email
  fill_in "Password", with: user.password
  click_button "Sign in"
  # Sign in when not using Capybara as well.
  cookies[:remember_token] = user.remember_token
end

非常感谢任何理解这个问题的帮助!

2 个答案:

答案 0 :(得分:3)

您可以在更新个人资料时自动重新签名:

def update
  if @user.update_attributes(params[:user])
     sign_in @user
     flash[:success] = "Profile updated"
     redirect_to @user
  else
    render 'edit'
  end
end

答案 1 :(得分:0)

我相信您在列表9.6中缺少spec / support / utilities.rb中sign_in(user)方法的更新:

def sign_in(user, options = {})
  if options[:nocapybara]
    remember_token = User.new_remember_token
    cookies[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
  else
    visit signin_path
    fill_in "Email",     with: user.email.upcase
    fill_in "Password",  with: user.password
    click_button "Sign in"
  end
end

还缺少app / helpers / sessions_helper.rb中同名方法的更新,您可以在清单8.2.3中找到:

def sign_in(user)
  remember_token = User.new_remember_token
  cookies.permanent[:remember_token] = remember_token
  user.update_attribute(:remember_token, User.encrypt(remember_token))
  self.current_user = user
end