我正在研究Michael Hartl的Rails教程。我来Chapter 9, Exercise 1。它要求您添加测试以验证admin
类的User
属性是否无法访问。这是带有不相关部分的User类注释掉:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
attr_protected :admin
# before_save methods
# validations
# private methods
end
这是我用来验证admin
属性无法访问的测试。
describe User do
before do
@user = User.new(
name: "Example User",
email: "user@example.com",
password: "foobar123",
password_confirmation: "foobar123")
end
subject { @user }
describe "accessible attributes" do
it "should not allow access to admin" do
expect do
@user.admin = true
end.should raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
end
测试失败。它表示尽管admin
属性受到保护,但没有出现任何错误。我怎样才能通过考试?
答案 0 :(得分:5)
来自Ruby文档:
批量分配安全性提供了一个界面,用于保护最终用户分配的属性。
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html
尝试使用此代码
describe "accesible attributes" do
it "should not allow access to admin" do
expect do
User.new(admin: true)
end.should raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
答案 1 :(得分:3)
正如Rails文档声称的attr_protected
此宏中命名的属性受质量分配保护,例如new(attributes),update_attributes(attributes)或attributes =(attributes)。
因此您可以手动更改字段。 'attr_protected'只是关于质量分配。
答案 2 :(得分:1)
这仅适用于大量分配,例如从表单提交中设置字段。尝试这样的事情:
@user.update_attrtibutes(:admin => true)
@user.admin.should be_false
答案 3 :(得分:1)
@agaved。这个答案可能会迟到,你可能已经有了答案,但我想回答你的问题,这可能有助于其他人。
了解update_attributes
与直接分配的不同之处的最佳方法
@user.admin = true
是尝试在您的控制台中执行此操作。如果您正在阅读Hartl的教程,请尝试以下方法:
@user = User.first
@user.admin?
=> true
@user.admin = false
=> false
直接分配可以将用户属性admin的值从true
更改为false
,而不会引发质量分配错误。这是因为当您使用无法访问的属性调用update_attributes
或创建新用户User.new
时,会引发批量分配错误。换句话说,当用户尝试更新(attribute_update)
或创建User.new(admin: true)
具有她无法访问的属性的新用户时,Rails会引发批量分配错误。在上述情况下,直接分配不使用用户控制器的create或update方法。
它们是非常相似的代码片段,因为您可以使用直接赋值在上述情况下使用@user.save!(validate: false)
直接在IRB中强制更改admin属性,但正如我上面所说,这不使用创建或更新您的用户控制器的方法,因此,它不会抛出错误。
我希望有帮助,this帮助了我。
答案 4 :(得分:1)
[剧透警告:如果你试图自己解决Hartl的书中的练习,我很确定我即将给出答案。尽管已经接受的答案是有趣的信息,但我并不相信这是Hartl所想到的,因为这需要本书未涵盖的知识,也不会通过网络行为或使用将其与更新相关联。他提供的测试。]
我认为如果我做对了,你可能会认为这个练习比实际练习困难得多。首先,你误解了提示:
提示:您的第一步应该是将admin添加到user_params中的允许参数列表中。
它没有说改变它在课堂上的attr声明。它说要修改辅助函数user_params。所以我将它添加到users_controller.rb中的列表中:
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, :admin)
end
接下来,我将代码清单9.48中的代码复制到spec / requests / user_pages_spec.rb中的指定位置:
require 'spec_helper'
describe "User pages" do
.
.
.
describe "edit" do
.
.
.
describe "forbidden attributes" do
let(:params) do
{ user: { admin: true, password: user.password,
password_confirmation: user.password } }
end
before do
sign_in user, no_capybara: true
patch user_path(user), params
end
specify { expect(user.reload).not_to be_admin }
end
end
end
然后测试失败,显示可以传入admin参数,从而将普通用户更改为管理员,这不是您想要允许的:
$ rspec spec
.....................[edited out dots].................................F
Failures:
1) User pages edit forbidden attributes
Failure/Error: specify { expect(user.reload).not_to be_admin }
expected admin? to return false, got true
# ./spec/requests/user_pages_spec.rb:180:in `block (4 levels) in <top (required)>'
Finished in 4.15 seconds
91 examples, 1 failure
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:180 # User pages edit forbidden attributes
然后,为了无法通过网络操作传递管理员值,我只需从可接受的user_params列表中删除:admin,撤消第一个更改:
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
现在尝试使用新的管理员值修补用户失败...并且测试成功,验证&#34; admin
属性无法通过网络进行编辑。&#34 ;
$ rspec spec
...........................................................................................
Finished in 4.2 seconds
91 examples, 0 failures
答案 5 :(得分:0)
根据提示,我首先在app / models / user.rb中将:admin
添加到attr_accessible
以红色开头。
然后我添加了测试:
describe "admin attribute" do
it "should not be accessible" do
expect do
@user.update_attributes(:admin => true)
end.to raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
到规格并得到一个红色。
从user.rb中删除:admin
我得到绿色。到目前为止一切顺利。
令我困惑的是为什么我应该使用sintax:
@user.update_attributes(:admin => true)
而不是@user.admin = true
(我检查过,在这种情况下它不起作用)。