使Rails类属性无法访问 - Rails教程第9章,练习1

时间:2012-05-25 05:06:23

标签: ruby-on-rails railstutorial.org

我正在研究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属性受到保护,但没有出现任何错误。我怎样才能通过考试?

6 个答案:

答案 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(我检查过,在这种情况下它不起作用)。