ActiveRecord 的更新方法失败,因为 UNIQUE 约束失败:items.id
update method of ActiveRecord failed because UNIQUE constraint failed: items.id
在这种情况下,
product = <Item id: 4, url: nil, memo: nil, created_at: "2015-11-07 09:48:36", updated_at: "2015-11-07 09:48:36", Totalweight: 390.0, Perweight: nil, price: 1000>
attr = {"id"=>4, "tag_list"=>"peanuts", "price"=>1000, "url"=>nil, "Totalweight"=>390, "memo"=>nil}
我确实更新了项目的记录。
product.update!(attr)
但错误说,
SQLite3::ConstraintException UNIQUE constraint failed: items.id
!! #<ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: items.id: INSERT INTO "items" ("id", "price", "Totalweight", "created_at", "updated_at", "url") VALUES (?, ?, ?, ?, ?, ?)>
当然id是一样的,因为我要更新记录。
我试过了
product.update_attributes(attr)
也显示同样的错误。
问题是如何更新这个 Item 对象?
如果未设置 id,ActiveRecord 的保存方法将起作用。
此外,更多信息,
我正在使用 gem 'roo' 导入 Excel、CSV 文件并可以解析。
https://github.com/roo-rb/roo
参数行来自 gem 'roo'
这是代码,
COLUMN = ["id","tag_list","price","url","Perweight","Totalweight", "memo", "id", "created_at", "updated_at"]
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
if Item.find(row["id"]) then
product = Item.new
attr = row.slice(*COLUMN)
# product.attributes = attr
product.update(attr)
else
product = Item.new
attr = row.slice(*COLUMN)
product.attributes = attr
product.save!
end
end
end
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when ".csv" then
Roo::Spreadsheet.open(file.path, extension: :csv)
when ".xls" then
Roo::Spreadsheet.open(file.path, extension: :xls)
when ".xlsx" then
Roo::Spreadsheet.open(file.path, extension: :xlsx)
else raise "Unknown file type: #{file.original_filename}"
end
end
您已经在检查项目是否存在 - 这很好。
但是您不是在升级现有项目,而是在创建一个新项目,即使已经存在具有相同 ID 的项目,这就是您收到错误的原因。
有两种方法可以解决这个问题 - 第一种有点冗长,但更接近您已有的方法:
product = Item.find(row["id"])
if product then
attr = row.slice(*COLUMN)
# Update the existing product
product.update(attr)
else
...
end
但是,既然你对产品对象做同样的事情,不管它是否存在,你也可以这样做:
# This will either find an existing product, or initialize a new one with the ID
product = Item.find_or_initialize_by(id: row["id"])
attr = row.slice(*COLUMN)
product.attributes = attr
product.save!
在这种情况下,
product = <Item id: 4, url: nil, memo: nil, created_at: "2015-11-07 09:48:36", updated_at: "2015-11-07 09:48:36", Totalweight: 390.0, Perweight: nil, price: 1000>
attr = {"id"=>4, "tag_list"=>"peanuts", "price"=>1000, "url"=>nil, "Totalweight"=>390, "memo"=>nil}
我确实更新了项目的记录。
product.update!(attr)
但错误说,
SQLite3::ConstraintException UNIQUE constraint failed: items.id
!! #<ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: items.id: INSERT INTO "items" ("id", "price", "Totalweight", "created_at", "updated_at", "url") VALUES (?, ?, ?, ?, ?, ?)>
当然id是一样的,因为我要更新记录。 我试过了
product.update_attributes(attr)
也显示同样的错误。
问题是如何更新这个 Item 对象?
如果未设置 id,ActiveRecord 的保存方法将起作用。
此外,更多信息, 我正在使用 gem 'roo' 导入 Excel、CSV 文件并可以解析。 https://github.com/roo-rb/roo 参数行来自 gem 'roo'
这是代码,
COLUMN = ["id","tag_list","price","url","Perweight","Totalweight", "memo", "id", "created_at", "updated_at"]
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
if Item.find(row["id"]) then
product = Item.new
attr = row.slice(*COLUMN)
# product.attributes = attr
product.update(attr)
else
product = Item.new
attr = row.slice(*COLUMN)
product.attributes = attr
product.save!
end
end
end
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when ".csv" then
Roo::Spreadsheet.open(file.path, extension: :csv)
when ".xls" then
Roo::Spreadsheet.open(file.path, extension: :xls)
when ".xlsx" then
Roo::Spreadsheet.open(file.path, extension: :xlsx)
else raise "Unknown file type: #{file.original_filename}"
end
end
您已经在检查项目是否存在 - 这很好。 但是您不是在升级现有项目,而是在创建一个新项目,即使已经存在具有相同 ID 的项目,这就是您收到错误的原因。
有两种方法可以解决这个问题 - 第一种有点冗长,但更接近您已有的方法:
product = Item.find(row["id"])
if product then
attr = row.slice(*COLUMN)
# Update the existing product
product.update(attr)
else
...
end
但是,既然你对产品对象做同样的事情,不管它是否存在,你也可以这样做:
# This will either find an existing product, or initialize a new one with the ID
product = Item.find_or_initialize_by(id: row["id"])
attr = row.slice(*COLUMN)
product.attributes = attr
product.save!