Hartl Rails 教程第 9 章,"test_should_redirect_destroy_when_not_logged_in" 错误?
Hartl Rails Tutorial Ch9, "test_should_redirect_destroy_when_not_logged_in" error?
通过 Hartl 的教程,在第 9 章中,清单 9.56 产生以下错误,将 'admin?' 显示为未定义的方法。
我已经检查(并重新检查)自上次绿色测试以来修改过的 2 段代码。难倒了。
ERROR["test_should_redirect_destroy_when_not_logged_in", UsersControllerTest, 2016-02-26 21:29:01 -0500]
test_should_redirect_destroy_when_not_logged_in#UsersControllerTest (1456540141.41s)
NoMethodError: NoMethodError: undefined method `admin?' for nil:NilClass
app/controllers/users_controller.rb:73:in `admin_user'
test/controllers/users_controller_test.rb:48:in `block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:47:in `block in <class:UsersControllerTest>'
app/controllers/users_controller.rb:73:in `admin_user'
test/controllers/users_controller_test.rb:48:in `block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:47:in `block in <class:UsersControllerTest>'
39/39: [==========================================================] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.97767s
39 tests, 152 assertions, 0 failures, 1 errors, 0 skips
请注意,admin 字段是在迁移过程中添加到数据库中的,据我所知应该 自动生成布尔值 admin?方法
class AddAdminToUsers < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, default: false
end
end
users_controller_test.rb 显然是问题所在,特别是在以下几行:
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete :destroy, id: @user
...完整的文件如下所示:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
@user = users(:michael)
@other_user = users(:archer)
end
test "should redirect index when not logged in" do
get :index
assert_redirected_to login_url
end
test "should get new" do
get :new
assert_response :success
end
test "should redirect edit when not logged in" do
get :edit, id: @user
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect to update when not logged in" do
patch :update, id: @user, user: { name: @user.name, email: @user.email }
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect edit when logged in as wrong user" do
log_in_as(@other_user)
get :edit, id: @user
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect update when logged in as wrong user" do
log_in_as(@other_user)
patch :update, id: @user, user: {name: @user.name, email: @user.email }
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete :destroy, id: @user
end
assert_redirected_to login_url
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(@other_user)
assert_no_difference 'User.count' do
delete :destroy, id: @user
end
assert_redirected_to root_url
end
end
这里是users.yaml
的内容
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
mallory:
name: Mallory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
从错误消息来看,您似乎是在 current_user
上调用 admin?
,但您没有任何人登录,因此 current_user
为零。尝试做 current_user.try(:admin?)
而不是 return nil 如果 current_user 也是 nil.
补充一下。虽然 bf34 的答案可以解决问题,但它可能不是正确的解决方案。
目前正在学习本教程并遇到了同样的问题。纯粹是current_user.admin的原因?是因为如果没有登录,它甚至不应该到达此检查。
重新阅读我的代码后,我发现我没有 logged_in_user 的 before_action 用于 destroy 方法(见第二行)。
app/controllers/users_controller.rb:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
log_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update_attributes(user_params)
# Handle a successful update.
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
通过 Hartl 的教程,在第 9 章中,清单 9.56 产生以下错误,将 'admin?' 显示为未定义的方法。
我已经检查(并重新检查)自上次绿色测试以来修改过的 2 段代码。难倒了。
ERROR["test_should_redirect_destroy_when_not_logged_in", UsersControllerTest, 2016-02-26 21:29:01 -0500]
test_should_redirect_destroy_when_not_logged_in#UsersControllerTest (1456540141.41s)
NoMethodError: NoMethodError: undefined method `admin?' for nil:NilClass
app/controllers/users_controller.rb:73:in `admin_user'
test/controllers/users_controller_test.rb:48:in `block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:47:in `block in <class:UsersControllerTest>'
app/controllers/users_controller.rb:73:in `admin_user'
test/controllers/users_controller_test.rb:48:in `block (2 levels) in <class:UsersControllerTest>'
test/controllers/users_controller_test.rb:47:in `block in <class:UsersControllerTest>'
39/39: [==========================================================] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.97767s
39 tests, 152 assertions, 0 failures, 1 errors, 0 skips
请注意,admin 字段是在迁移过程中添加到数据库中的,据我所知应该 自动生成布尔值 admin?方法
class AddAdminToUsers < ActiveRecord::Migration
def change
add_column :users, :admin, :boolean, default: false
end
end
users_controller_test.rb 显然是问题所在,特别是在以下几行:
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete :destroy, id: @user
...完整的文件如下所示:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def setup
@user = users(:michael)
@other_user = users(:archer)
end
test "should redirect index when not logged in" do
get :index
assert_redirected_to login_url
end
test "should get new" do
get :new
assert_response :success
end
test "should redirect edit when not logged in" do
get :edit, id: @user
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect to update when not logged in" do
patch :update, id: @user, user: { name: @user.name, email: @user.email }
assert_not flash.empty?
assert_redirected_to login_url
end
test "should redirect edit when logged in as wrong user" do
log_in_as(@other_user)
get :edit, id: @user
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect update when logged in as wrong user" do
log_in_as(@other_user)
patch :update, id: @user, user: {name: @user.name, email: @user.email }
assert flash.empty?
assert_redirected_to root_url
end
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
delete :destroy, id: @user
end
assert_redirected_to login_url
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(@other_user)
assert_no_difference 'User.count' do
delete :destroy, id: @user
end
assert_redirected_to root_url
end
end
这里是users.yaml
的内容# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
mallory:
name: Mallory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
从错误消息来看,您似乎是在 current_user
上调用 admin?
,但您没有任何人登录,因此 current_user
为零。尝试做 current_user.try(:admin?)
而不是 return nil 如果 current_user 也是 nil.
补充一下。虽然 bf34 的答案可以解决问题,但它可能不是正确的解决方案。
目前正在学习本教程并遇到了同样的问题。纯粹是current_user.admin的原因?是因为如果没有登录,它甚至不应该到达此检查。
重新阅读我的代码后,我发现我没有 logged_in_user 的 before_action 用于 destroy 方法(见第二行)。
app/controllers/users_controller.rb:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
log_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update_attributes(user_params)
# Handle a successful update.
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end