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


67

我使用了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表中创建的,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")

我对Rails 4不太了解,但是我认为这个问题是Rails 3的问题。config/application.rbRails 4中的默认硬编码配置为空!
boulder_ruby 2014年

Answers:


140

不要attr_accessor与混淆attr_accessible。Accessor内置在Ruby中,并定义了getter方法model_instance.foo # returns something-和setter方法- model_instance.foo = 'bar'

可访问性是由Rails定义的,并使该属性可分配质量(与相反attr_protected)。

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


现在,当我耙种子文件时,收到关于邀请的“未知属性”错误。我知道我在数据库中有这个字段。它在迁移文件中……
picardo

它在迁移文件中,但是您运行迁移了吗?发布您的种子文件。
罗伯特·施派克

您是否更新了其他内容?即使那是错误的,您的模型中仍然有attr_accessor。
罗伯特·史派克

这可能与STI对所有子类仅使用一个表这一事实有关,Dave Simms指出。我有一个Doctors表,该表具有Invitations字段,但应该在users表中。噢!
picardo

如果要对User表进行子类化,是否在User本身中检查了attr_accessible?或attr_protected,但我怀疑是前者。您可以通过在子类中调用#attr_accessible来添加可在子类中访问的字段。
弗朗索瓦·博索莱尔

11

要以不安全的方式将您的应用程序合并在一起,完全不适合生产模式:

转到/config/application.rb向下滚动至找到的末尾

{config.active_record.whitelist_attributes = true}

将其设置为false。

编辑/顺便说一句(经过4个月的红宝石密集型工作,包括为期11周的研讨会):DHH认为,对于新手(他的话),“正常运行”比“​​非常安全”更为重要。

忠告:许多经验丰富的Rails开发人员对希望您这样做非常有热情。

更新:3年后,另一种实现此目的的方法-不安全,但是比上述解决方案更好,这可能是因为您必须针对每个模型都这样做

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

35
即使有“早期编码”的警告,这也是一个非常糟糕的建议。开发人员何时有机会返回并重构其整个应用程序?从一开始就正确地做。
toxaq 2012年

4
“请记住,这是一个安全漏洞,但您以后可以处理”。您打算什么时候处理它?后来,什么时候生产?我刚刚添加了“您对attr_accessible有何看法?” 我的面试问题清单。
toxaq 2012年

我可以建议修改以澄清您的答案吗?从您的帖子中,还不能完全清楚默认值是更安全的方法,将其更改为false可以轻松访问模型属性,但会打开安全漏洞。
神剑

1
如果您要从Rails 3.0x迁移到rails 3.2.8,这会有所帮助,暂时禁用此功能,然后稍后再次启用它
Amol Pujari 2012年

那么,您能解释一下这是一个安全漏洞吗?我的意思是,为了使用update_atttributes,您需要访问Rails应用程序本身的范围。如果有人拥有该应用程序,则该应用程序已经被破坏。禁用update_attributes不会使您的应用程序更安全。
RedMage 2014年

2

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

编辑:您不需要医生表,您需要具有类型列的用户表来处理Rails单表继承。邀请将在用户表上。嗯,我看到您在添加的代码示例中确实输入了用户。摆脱医生表,将邀请移交给用户,我认为您应该没事。也摆脱attr_accessor。并不需要。

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

编辑:另外,您确定只希望在创建时验证邀请的存在,而不是更新吗?


但是,当我不使用它时,Rails会在我耙种子文件时告诉我“未找到方法”。在那种情况下我该怎么办?
picardo

您可以发布模型代码并执行耙任务吗?也是创建模型的迁移。确保这些列在数据库中创建。
Dave Sims 2010年

2

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



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.