“警告:无法批量分配受保护的属性”

时间:2010-10-15 16:41:08

标签: ruby-on-rails activerecord devise

我使用RESTful技术生成模型(事实上,我正在使用Devise gem,它为我做了这个),并且我已经为模型添加了名为first_name和last_name的新字段。迁移进展顺利。我将attr_accessor:first_name,:last_name添加到模型中,并期望它能正常工作。但是当我尝试使用Doctor.create({:first_name =>“MyName”})等大量分配新实例时,我收到的错误是我无法批量分配受保护的属性。

我认为使用attr_accessor的重点是绕过模型字段的保护。你能帮我理解这个消息吗?

编辑:哦,顺便说一下也没有创建记录。我认为它们应该是因为这只是一个警告,但它们不在数据库中。

Edit2:这是我的模特

class Doctor < User
  has_many :patients
  has_many :prescriptions, :through=> :patients

  validates_presence_of :invitations, :on => :create, :message => "can't be blank"

  attr_accessor :invitations
end

和架构,它没有first_name和last_name,因为它们是在users表中创建的,这是医生的祖先。我使用单表继承。

create_table :doctors do |t|
  t.integer :invitations

  t.timestamps
end

这是迁移以更改用户表

add_column :users, :first_name, :string
add_column :users, :last_name, :string
add_column :users, :type, :string

编辑:这是种子文件。我不包括truncate_db_table方法,但它可以工作。

%w{doctors patients}.each do |m|
  truncate_db_table(m)  
end  

Doctor.create(:invitations=>5, :email=>"email@gmail.com", :first_name=>"Name", :last_name=>"LastName")
Patient.create(:doctor_id=>1, :gender=>"male", :date_of_birth=>"1991-02-24")

6 个答案:

答案 0 :(得分:140)

请勿将attr_accessorattr_accessible混淆。 Accessor内置于Ruby中,定义了一个getter方法 - model_instance.foo # returns something - 和一个setter方法 - model_instance.foo = 'bar'

Accessible由Rails定义,并使属性可以分配(与attr_protected相反)。

如果first_name是模型数据库表中的字段,那么Rails已经为该属性定义了getter和setter。您需要做的就是添加attr_accessible :first_name

答案 1 :(得分:12)

以不安全的方式一起破解你的应用程序,完全不适合生产模式:

转到/config/application.rb向下滚动到找到

的末尾
{config.active_record.whitelist_attributes = true}

将其设为false。

EDIT / btw(经过4个月的红宝石密集型工作,包括为期11周的研讨会): DHH认为, for noobies (他的话),“up and running”比“非常安全”更重要。

建议:虽然这个答案(我认为我的第一个关于stackoverflow的问题)现在是+6,但它的历史一直低至-4,这意味着很多经验丰富的rails开发人员感到非常热情关于希望你这样做。

更新: 3年后,另一种方法 - 再次,不安全,但比上述解决方案更好,可能是因为你必须为每个模型做到这一点

class ModelName < ActiveRecord::Base
  column_names.each do |col|
    attr_accessible col.to_sym
  end
  ...
end

答案 2 :(得分:2)

这里不要使用attr_accessor。 ActiveRecord在模型上自动创建。此外,如果抛出验证或质量分配错误,ActiveRecord将不会创建记录。

编辑:您不需要医生表,您需要一个带有类型列的用户表来处理Rails Single Table Inheritance。邀请将在用户表上。啊,我在你添加的代码示例中看到你确实有用户类型。摆脱医生表,将邀请转移给用户,我认为你应该没问题。也摆脱了attr_accessor。不需要。

请记住,rails STI对特定模型的所有类和子类使用相同的表。您的所有Doctor记录都将是users表中的行,其类型为'doctor'

编辑:此外,您确定只想在创建时验证邀请,而不是更新吗?

答案 3 :(得分:2)

attr_accessible : variable1, variable2添加到您的表路径文件中。

答案 4 :(得分:0)

同意@Robert Speicher的答案但我强烈建议您使用Strong parameter代替attr_accessible来防止群发抵押。

干杯!

答案 5 :(得分:0)

如果要禁用单个呼叫的群发分配保护(但不能全局禁用),则可以使用:without_protection => true选项。我发现这对于迁移和其他将哈希键/值进行硬编码或以其他方式认为是安全的地方很有用。

此处的示例(同样适用于rails 3.2):https://apidock.com/rails/v3.1.0/ActiveRecord/Base/create/class