gpt4 book ai didi

ruby-on-rails - 为什么 before_actions 声明的顺序很重要?

转载 作者:行者123 更新时间:2023-12-03 18:20:00 27 4
gpt4 key购买 nike

我正在学习 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 时,出现四个错误。但是当我改变顺序时,没有。我看不到对声明顺序的任何依赖。我想知道为什么顺序很重要。

这是我的问题...这里是关于我正在运行的代码的更多信息。

因为我在本书的最后,有很多代码,所以我会尽量包含我认为可能相关的部分。

声明中列出的两个 Action 定义在同一个类的末尾:

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

第三个定义在UsersController的父类ApplicationController中的SessionsHelper中:

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 的代码并确保我的代码准确地反射(reflect)了他的代码,我花了一段时间才找到这个问题。一段时间后我发现了这个顺序差异并进行了更改,突然我的测试全部通过了。我已经来回切换了几次顺序,以确保它是顺序,并且只有顺序在变化并且有所不同。我想了解一下,这样当我编写自己的代码而不是复制别人的代码时,我就不会遇到类似的问题。

最佳答案

看起来在这个 Controller 中,signed_in_user 充当守卫以确保在继续之前有一个有效的 current_user(如果没有,重定向到登录页面,将在其中创建)。

您的第四次测试暴露了这一点 - admin? 未定义,因为 admin_usersigned_in_user 之前被调用。当 signed_in_user 首先被调用时,admin_user 不会被调用,除非实际上有一个有效的 current_user 来调用 admin? 上。所以这里实际上依赖于过滤器的顺序 - signed_in_user必须首先被调用,因为它确保有一个有效的current_user,并且其他过滤器假设这已经发生了。

关于ruby-on-rails - 为什么 before_actions 声明的顺序很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25049401/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com