本人在看《Ruby on Rails Tutorial(第二版)》学习 Rails。看完第九章修改用户信息。在做练习六时,遇到了一些诡异问题。陈述如下:
练习六( http://railstutorial-china.org/chapter9.html#sec-9-6 )题目如下: 已经登录的用户就没必要再访问 Users 控制器的 new 和 create 动作了,修改程序,如果登录后的用户访问这些地址时,转向到网站首页。
这个练习功能正常实现,实现方式如下(以下代码的第一行为文件路径):
#/app/helpers/sessions_helper.rb
module SessionsHelper
def signed_in?
!current_user.nil?
end
def current_user
@current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def forbid_signed_user # 这是我添加的跳转辅助方法
if signed_in?
redirect_to root_path
return
end
end
end
UserController
中的实现如下:
# /app/controllers/users_controller.rb
class UsersController < ApplicationController
# …
before_filter :forbid_signed_user, only:[:new, :create]
def create
@user = User.new(params[:user])
if @user.save
sign_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
# …
end
到这里一切正常。再我们接着往下看。
我想 既然是登陆用户,也没必要访问登陆页面了。所以,我想针对登陆页面也添加如此限制。具体实现如下:
# /app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
before_filter :forbid_signed_user, only:[:new, :create] # 使用filter来实现
def new
end
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_back_or user
else
flash.now[:error] = 'Invalid email/password combination' # Not quite right!
render 'new'
end
end
# …
end
然后,问题就来了。测试用例的报错信息如下:
Failures:
1) UserPages index delete links as an admin user
Failure/Error: sign_in admin
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Email' found
# (eval):2:in `fill_in'
# ./spec/support/utilities.rb:5:in `sign_in'
# ./spec/requests/user_pages_spec.rb:36:in `block (5 levels) in <top (required)>'
2) UserPages index delete links as an admin user should be able to delete another user
Failure/Error: sign_in admin
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Email' found
# (eval):2:in `fill_in'
# ./spec/support/utilities.rb:5:in `sign_in'
# ./spec/requests/user_pages_spec.rb:36:in `block (5 levels) in <top (required)>'
3) UserPages index delete links as an admin user
Failure/Error: sign_in admin
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Email' found
# (eval):2:in `fill_in'
# ./spec/support/utilities.rb:5:in `sign_in'
# ./spec/requests/user_pages_spec.rb:36:in `block (5 levels) in <top (required)>'
Finished in 13.29 seconds
83 examples, 3 failures
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:40 # UserPages index delete links as an admin user
rspec ./spec/requests/user_pages_spec.rb:41 # UserPages index delete links as an admin user should be able to delete another user
rspec ./spec/requests/user_pages_spec.rb:44 # UserPages index delete links as an admin user
错入信息中提到的两个文件如下:
utilities.rb
代码如下:
# /spec/support/utilities.rb
include ApplicationHelper
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 Capybars as well
cookies[:remember_token] = user.remember_token
end
user_pages_spec.rb
中部分代码如下:
# /spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "UserPages" do
subject { page }
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
sign_in user
visit users_path
end
it { should have_selector('title', text:'All users') }
it { should have_selector('h1', text: 'All users') }
describe "pagination" do
before(:all) { 80.times { FactoryGirl.create(:user) } }
after(:all) { User.delete_all }
it { should have_selector('div.pagination') }
it "should list each user" do
User.paginate(page: 1).each do |user|
page.should have_selector('li', text:user.name)
end
end
end
describe "delete links" do
it { should_not have_link('delete') }
describe "as an admin user " do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
it { should have_link('delete', href: user_path(User.first)) }
it "should be able to delete another user" do
expect { click_button('delete').to change(User, :count).by(-1) }
end
it { should_not have_link('delete', href: user_path(admin)) }
end
end
end
end
疑问:为啥会有这些问题? 是不是因为在如下代码:
describe "as an admin user " do
let(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
visit users_path
end
之前已经登录
过来?登陆代码 (就是user_pages_spec.rb
开头部分的代码) 如下:
describe "index" do
let(:user) { FactoryGirl.create(:user) }
before(:each) do
sign_in user
visit users_path
end
再次疑问:每一个describe "tips" do…end
块(暂且成为子describe块
)和上层的describe "tips" do…end
块(暂且成为父describe块
)之间是什么关系?父describe块
的操作会对子describe块
产生什么影响?
代码:
https://github.com/diguage/rortutorial
说明:我已经将第九章的代码提交到了develop
分支,还没有将第九章的代码合并到master
分支上。下载测试代码时,请注意。谢谢!
《Ruby on Rails Tutorial(第二版)》中文版: http://railstutorial-china.org/