1

我正在尝试编写让管理员上传充满法官的 CSV 的能力。当我尝试执行此操作时,我收到了一个 AssignmentError。这让我很困惑,因为我在所有相关变量上都使用了 attr_accessible。我所做的所有研究表明,如果您使用 attr_accessible,您应该能够批量分配变量。

我仍然是一个 Rails 新手,所以如果我在做一些非常愚蠢的事情,请原谅。

测试 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

相关控制器:

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

1 回答 1

2

为您提供的哈希row.to_hash将如下所示:

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

这里的问题是键是大写的字符串。'电子邮件'!='电子邮件'。

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

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

在将它们传递给之前,您应该将键清理为 snake_case(与其各自的可访问属性相同)create!,或者在 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 文件的格式,它可以使您的导入脚本更加健壮。它还使您有机会在将值写入数据库之前对其进行清理。

于 2013-07-24T00:23:06.017 回答