Ruby-on-rails “警告:不能批量分配受保护的属性”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3944288/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:23:37  来源:igfitidea点击:

"WARNING: Can't mass-assign protected attributes"

ruby-on-railsactiverecorddevise

提问by picardo

I have used RESTful techniques to generate a model (in fact, I am using Devise gem, which does that for me), and I have added new fields called first_name and last_name to the model. Migration went fine. I added attr_accessor :first_name, :last_name to the model and expected it would just work. But when I try to mass-assign new instances with Doctor.create({:first_name=>"MyName"}) etc., I am getting errors saying I can't mass-assign protected attributes.

我使用了 RESTful 技术来生成模型(实际上,我使用的是 Devise gem,它为我完成了这项工作),并且我向模型添加了名为 first_name 和 last_name 的新字段。迁移很顺利。我在模型中添加了 attr_accessor :first_name, :last_name 并希望它可以正常工作。但是当我尝试使用 Doctor.create({:first_name=>"MyName"}) 等批量分配新实例时,我收到错误消息,说我无法批量分配受保护的属性。

I thought the whole point of using attr_accessor was to get around the protectedness of the fields of a model. Can you help me make sense of this message?

我认为使用 attr_accessor 的全部目的是绕过模型字段的保护。你能帮我理解这条消息吗?

Edit: oh, and by the way the records do not get created either. I thought they should be since this is just a warning, but they are not on the database.

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

Edit2: here is my model

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

and the schema, which doesn't have the first_name and last_name because they are created in the users table, which is the ancestor of doctors. I used single table inheritance.

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

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

  t.timestamps
end

and this is the migration to change the users table

这是更改用户表的迁移

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

EDIT: here is the seed file. I am not including the truncate_db_table method, but it works.

编辑:这是种子文件。我不包括 truncate_db_table 方法,但它有效。

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

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

回答by Robert Speicher

Don't confuse attr_accessorwith attr_accessible. Accessor is built into Ruby and defines a getter method - model_instance.foo # returns something- and a setter method - model_instance.foo = 'bar'.

不要attr_accessorattr_accessible. Accessor 内置于 Ruby 中并定义了一个 getter 方法 - model_instance.foo # returns something- 和一个 setter 方法 - model_instance.foo = 'bar'

Accessible is defined by Rails and makes the attribute mass-assignable (does the opposite of attr_protected).

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

If first_nameis a field in your model's database table, then Rails has already defined getters and setters for that attribute. All you need to do is add attr_accessible :first_name.

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

回答by boulder_ruby

To hack your app together in an insecure way totally unfit for production mode:

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

Go to /config/application.rb Scroll down towards the end where you'll find

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

{config.active_record.whitelist_attributes = true}

Set it to false.

将其设置为假。

EDIT/btw (after 4 months of ruby-intensive work including an 11 week workshop): DHH believes that, for noobies(his words), "up and running" is more important than "very secure".

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

BE ADVISED: A a lot of experienced rails developers feel very passionate about notwanting you to do this.

建议:许多有经验的 Rails 开发人员都非常热衷于希望您这样做。

UPDATE: 3 years later, another way to do this -- again, not secure, but better than the above solution probably because you have to do it for each model

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

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

回答by Aneez

Add attr_accessible : variable1, variable2to your table route file.

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

回答by Dave Sims

Don't use attr_accessor here. ActiveRecord creates those automatically on the model. Also, ActiveRecord will not create a record if a validation or mass-assignment error is thrown.

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

EDIT: You don't need a doctors table, you need a users table with a type column to handle Rails Single Table Inheritance. The invitations will be on the users table. Ah, I see in your added code sample you do have type on users. Get rid of the doctors table, move invitations over to users, and I think you should be ok. Also get rid of the attr_accessor. Not needed.

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

Keep in mind that rails STI uses the same table for all classes and subclasses of a particular model. All of your Doctor records will be rows in the users table with a type of 'doctor'

请记住,rails STI 对特定模型的所有类和子类使用相同的表。您的所有医生记录都将是用户表中类型为“医生”的行

EDIT: Also, are you sure you only want to validate presence of invitations on creation and not updates?

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

回答by Manish Shrivastava

Agree with @Robert Speicher answer But I will strongly recommend that You should use Strong parameterinstead of attr_accessibleto protect from mass asignment.

同意@Robert Speicher 的回答但我强烈建议您应该使用强参数而不是attr_accessible防止大规模分配。

Cheers!

干杯!

回答by Kyle McClellan

If you want to disable mass assignment protection for an individual call (but not globally), the :without_protection => trueoption can be used. I find this useful for migrations and other places where the keys/values of the hash are hard-coded or otherwise known to be safe.

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

Example here (works in rails 3.2 as well): https://apidock.com/rails/v3.1.0/ActiveRecord/Base/create/class

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