无法批量分配受保护的属性

时间:2012-03-16 18:46:08

标签: ruby-on-rails cucumber

我的features文件看到了这个:

Given there are the following users:
    | email              | password | admin |
    | admin@ticketee.com | password | true  |

我的user模型未将admin属性声明为attr_accessible以防止批量分配。因此,我对user_steps.rb文件进行了更改以解决此问题。

Given /^there are the following users:$/ do |table|
  table.hashes.each do |attributes|
   unconfirmed = attributes.delete("unconfirmed") == "true"
   @user = User.create!(attributes)
   @user.update_attribute("admin", attributes["admin"] == "true")
   @user.confirm! unless unconfirmed
 end
end

现在这应该按照本书 - Rails3的实际工作。我也检查了他们online repo上的代码。 用黄瓜运行它会产生以下错误:

Can't mass-assign protected attributes: admin (ActiveModel::MassAssignmentSecurity::Error)
  ./features/step_definitions/user_steps.rb:4:in `block (2 levels) in <top (required)>'
  ./features/step_definitions/user_steps.rb:2:in `each'
  ./features/step_definitions/user_steps.rb:2:in `/^there are the following users:$/'
  features/creating_projects.feature:7:in `Given there are the following users:'

非常感谢任何帮助。我真的不知道这里有什么问题。

非常感谢!

5 个答案:

答案 0 :(得分:8)

在用户模型中添加:

attr_accessible :admin

<强>更新

admin属性可以批量分配,任何黑客都可以通过发送参数轻松设置它。

答案 1 :(得分:3)

我通过更改步骤定义来实现此目的:

   Given /^there are the following users:$/ do |table|
      table.hashes.each do |attributes|
      unconfirmed = attributes.delete("unconfirmed") == "true"
      admin = attributes.delete("admin") == "true"
      @user = User.create!(attributes)
      @user.admin = admin
      @user.confirm! unless unconfirmed
      end
    end

答案 2 :(得分:1)

为什么不使用@user.admin = attributes["admin"] == "true"

您需要从属性哈希中删除管理员值 - 因此完整代码将是

admin = attributes.delete("admin") == "true"
...
@user = User.new(attributes)
@user.admin = admin
@user.save!

我改变了User.create!到User.new + @ user.save,因为您正在设置属性但不保存模型。如果@ user.confirm!保存模型你不会看到任何错误,但依靠其他方法的副作用并不是好习惯。最好是明确的。

答案 3 :(得分:1)

假设这是基于“Rails 3 in Action”,示例代码实际上有同样的问题。从日志中:

WARNING: Can't mass-assign protected attributes: admin
(0.1ms)  SELECT 1 FROM "users" WHERE "users"."email" = 'sfcarroll2@gmail.com' LIMIT 1
User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."confirmation_token" =     'f9zDB57RDXsziBdGpmnW' LIMIT 1

但是,在 config / environments / development.rb 文件中,未设置 mass_assignment_sanitizer 。默认情况下,新的rails 3.2项目将设置此项。如果注释掉,代码将执行。默认设置为:

config.active_record.mass_assignment_sanitizer = :strict

然后,示例代码使用私有方法 set_admin 设置属性。 这是一个很好的编码实践吗?我不确定但它有效。

顺便说一句,这本书很棒。

答案 4 :(得分:0)

我认为最简单的方法是:

Given /^there are the following users:$/ do |table|
  table.hashes.each do |attributes|
    unconfirmed = attributes.delete("unconfirmed") == "true" # this will delete the attribute unconfirmed from first
    # scenario on the signing_in.feature but it's also make a variable unconfirmed true (2 in one action)

    admin = attributes.delete("admin") == "true"

    @user = User.create!(attributes)

    @user.update_attribute("admin", "true") if admin

    # with the user and password, it will create the user as admin.
    @user.confirm! unless unconfirmed  # this is work for the second scenario check rails 3 in action page 152.
  end
end

这样您就可以从属性中删除admin属性,以便创建新用户; 没有质量分配属性错误。但是对于“测试”目的,如果admin为true,我们将admin变量分配给user.admin属性。这里的事情是你不会让用户模型上的管理员可以保护你的网站免受攻击,但我们这样做是为了通过我们的测试。在您的网站上,您必须实施一种安全的方式来在用户创建后更新用户。