当我使用Attr_Accessable时,为什么会出现质量分配错误?

时间:2013-07-24 00:16:10

标签: ruby-on-rails ruby mass-assignment

我试图为管理员编写一个上传完整法官的CSV的功能。当我尝试这样做时,我得到了一个AssignmentError。这对我来说真的很困惑,因为我在所有相关变量上使用了attr_accessible。我所做的所有研究都表明,如果你使用attr_accessible,你应该可以批量分配变量。

我还是铁杆新手,请原谅我,如果我做的事情真的很愚蠢。

测试CSV:

Name,Email,Competition_ID,Password
Brandon Schultz,b@schultz.com,1,12345678
Mr. Foo,foo@foo.com,1,12345678
Mr. Bar,bar@bar.com,1,12345678

错误讯息:

ActiveModel::MassAssignmentSecurity::Error in JudgesController#import
Can't mass-assign protected attributes: Name, Email, Competition_ID, Password

应用程序跟踪:

app/models/judge.rb:17:in `block in import'
app/models/judge.rb:16:in `import'
app/controllers/judges_controller.rb:32:in `import'

以下是相关模型:

class Judge < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :competition_id

  belongs_to :competition

def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|
            Judge.create! row.to_hash
        end
    end
end

Relevent Controller:

def import
  Judge.import(params[:file])
  redirect_to admin_portal_path, notice: "Products imported."
end

1 个答案:

答案 0 :(得分:2)

row.to_hash给你的哈希值如下:

{ 'Name' => 'Mr. Foo', 'Email' => 'foo@bar.com', ... }

这里的问题是键是大写的字符串。 'Email'!='email'。

如果要将哈希直接传递给create!,它需要完全符合属性名称,可以是字符串或符号:

{ 'name' => 'Mr. Foo', :email => 'foo@bar.com', ... }

在将密钥传递给create!之前,您应该将密钥清理为snake_case(与其各自的可访问属性相同),或者在CSV中更改它们。

您可能还会考虑从行哈希中单独分配每个属性,如果找不到值,则指定默认值。

hash = row.to_hash
judge = Judge.new
judge.name = hash['Name'] || hash['name'] || 'No name'
judge.email = hash['Email'] || hash['email']
judge.competition_id = hash['Competition_ID'] || hash['competition_id']

在这种情况下,这可能不是最好的做法,但如果您不能严格控制CSV文件的格式,它可以使您的导入脚本更加强大。它还使您有机会在将值写入数据库之前对其进行清理。