首页 > 解决方案 > 将从序列化中恢​​复的 ActiveRecord 项标记为持久性

问题描述

我有一种情况,已知在数据库中的一组项目是从序列化的 json 数组中恢复的,包括它们的id,因此可以将它们重塑为仅调用 new 的 ActiveRecord 模型实例,而无需访问数据库:

for itm in a do
   item = Item.new(itm)
   itmlist << item
emd

现在,问题是,如何告诉 ActiveRecord 这些元素已经持久化而不是新元素?如果item.new_record?为真,aitem.save将失败,因为 Rails 将插入而不是更新。

目标是确保 Rails 确实更新,而不需要对数据库进行任何额外查询。我得到的最接近的是

item = Item.new(itm)
item.instance_variable_set(:@new_record, false)

使用 ActiveRecord Internals 播放

标签: ruby-on-rails

解决方案


不确定我是否完全理解这个问题,但如果您只想更新所有项目,以下内容将起作用

a.each do |item_hash| 
  Item.find(item_hash["id"]).update(item_hash.except("id"))
end 

如果Item可能存在或可能不存在,那么

a.each do |item| 
  item = Item.find(item_hash["id"]) || Item.new 
  item.update(item_hash.except("id"))
end 

这些选项中的任何一个都不会处理验证失败。根据您的使用情况,以下可能有用

all_items = a.map do |item_hash| 
 item = Item.find(item_hash["id"]) || Item.new
 item.assign_attributes(item_hash.except("id"))
end
pass,fail = all_items.partition(&:save)

如果您只关心失败,您可以将其更改为:fail = all_items.reject(&:save)

如果有大量的项目,那么还有更多的替代方案可以避免如此多的查询。例如Item.where(id: a.map {|i| i["id"]})


推荐阅读