我正在研究Hartl的Ruby on Rails教程。在执行第11章时,我更新了UserController中的before_actions,并且认为订单不重要。所以我看起来像这样:
class UsersController < ApplicationController
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :signed_in_user,
only: [:index, :edit, :update, :destroy, :following, :followers]
他看起来像这样:
class UsersController < ApplicationController
before_action :signed_in_user,
only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
唯一的区别是陈述的顺序。
当我在我的运行rspec时,我得到四个错误。但是当我改变订单时,没有。我没有看到任何依赖声明的顺序。我想知道为什么订单很重要。
这是我的问题......以下是有关我正在运行的代码的更多信息。
因为我在本书的最后,有很多代码,所以我会尝试包含我认为可能相关的部分。
声明中列出的两个动作是在同一个类的末尾定义的:
class UsersController < ApplicationController
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :signed_in_user,
only: [:index, :edit, :update, :destroy, :following, :followers]
.
.
.
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
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
第三个是在SessionsHelper中定义的,它包含在ApplicationController中,是UsersController的父类:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include SessionsHelper
end
module SessionsHelper
.
.
.
def current_user=(user)
@current_user = user
end
def current_user
remember_token = User.digest(cookies[:remember_token])
@current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
def signed_in?
!current_user.nil?
end
.
.
.
如果运行rspec并按照我的方式运行代码,结果如下:
>rspec spec
.............................................................................F.
....FF.............................................F...........................
.............
Failures:
1) Authentication authorization for non-signed-in users when attempting to visit a protected page after signing in should render the desired protected page
Failure/Error: expect(page).to have_title('Edit user')
expected #has_title?("Edit user") to return true, got false
# ./spec/requests/authentication_pages_spec.rb:68:in `block (6 levels) in <top (required)>'
2) Authentication authorization for non-signed-in users in the Users controller visiting the edit page
Failure/Error: it { should have_title('Sign in') }
expected #has_title?("Sign in") to return true, got false
# ./spec/requests/authentication_pages_spec.rb:117:in `block (6 levels) in <top (required)>'
3) Authentication authorization for non-signed-in users in the Users controller submitting to the update action
Failure/Error: specify { expect(response).to redirect_to(signin_path) }
Expected response to be a redirect to <http://www.example.com/signin> but was a redirect to <http://www.example.com/>.
Expected "http://www.example.com/signin" to be === "http://www.example.com/".
# ./spec/requests/authentication_pages_spec.rb:122:in `block (6 levels) in <top (required)>'
4) User pages as admin user should not be able to delete it's own account
Failure/Error: expect { delete user_path(admin) }.not_to change(User, :count)
NoMethodError:
undefined method `admin?' for nil:NilClass
# ./app/controllers/users_controller.rb:95:in `admin_user'
# ./spec/requests/user_pages_spec.rb:79:in `block (5 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:79:in `block (4 levels) in <top (required)>'
Finished in 8.84 seconds
171 examples, 4 failures
Failed examples:
rspec ./spec/requests/authentication_pages_spec.rb:67 # Authentication authorization for non-signed-in users when attempting to visit a protected page after signing in should render the desired protected page
rspec ./spec/requests/authentication_pages_spec.rb:117 # Authentication authorization for non-signed-in users in the Users controller visiting the edit page
rspec ./spec/requests/authentication_pages_spec.rb:122 # Authentication authorization for non-signed-in users in the Users controller submitting to the update action
rspec ./spec/requests/user_pages_spec.rb:78 # User pages as admin user should not be able to delete it's own account
以下是authentication_pages_spec.rb中的失败测试:
describe "Authentication" do
subject { page }
.
.
.
describe "authorization" do
describe "for non-signed-in users" do
let(:user) { FactoryGirl.create(:user) }
describe "when attempting to visit a protected page" do
before do
visit edit_user_path(user)
sign_in(user)
end
describe "after signing in" do
it "should render the desired protected page" do
expect(page).to have_title('Edit user')
end
.
.
.
end
.
.
.
describe "in the Users controller" do
describe "visiting the edit page" do
before { visit edit_user_path(user) }
it { should have_title('Sign in') }
end
describe "submitting to the update action" do
before { patch user_path(user) }
specify { expect(response).to redirect_to(signin_path) }
end
describe "visiting the user index" do
before { visit users_path }
it { should have_title('Sign in') }
end
describe "visiting the following page" do
before { visit following_user_path(user) }
it { should have_title('Sign in') }
end
describe "visiting the followers page" do
before { visit followers_user_path(user) }
it { should have_title('Sign in') }
end
end
end
为了完成,让我补充一点,如果我将before_action声明的顺序更改为:
before_action :signed_in_user,
only: [:index, :edit, :update, :destroy, :following, :followers]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
所有测试均通过:
>rspec spec
..............................................................
..............................................................
...............................................
Finished in 8.82 seconds
171 examples, 0 failures
代码似乎在浏览器中完美运行。声明的顺序仅影响测试的结果。我花了一段时间才找到这个问题,回过头来看看Hartl的代码并确保我的确反映了他的问题。我在一段时间后发现了这个订单差异并进行了更改,突然我的测试全部通过了。我已经多次来回切换订单,以确保它是订单,只有订单正在改变,这才有所作为。我想了解所以当我编写自己的代码而不是复制别人的代码时,我没有遇到类似的问题。
答案 0 :(得分:1)
显然,before_action的顺序非常重要。
如果您在第一次使用signed_in_user
,则其他操作(例如correct_user或admin_user方法)可能没有current_user
变量可供使用。
首次登录时,您的代码可能会正常运行。但是,如果您在登录前调用操作,则会收到current_user is nil
的错误。
答案 1 :(得分:1)
看起来在这个控制器中,signed_in_user
充当警卫以确保在继续之前有一个有效的current_user
(如果没有,则重定向到登录页面,将创建一个)。
您的第四次测试将此消除 - admin?
未定义,因为在admin_user
之前调用了signed_in_user
。首先调用signed_in_user
时,除非实际上有admin_user
个有效current_user
,否则不会调用admin?
。所以这里实际上依赖于过滤器的顺序 - 首先要调用signed_in_user
,因为它确保存在有效的current_user
,而其他过滤器则认为这已经发生了。