防止Rails 5中重复的has_many记录
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了防止Rails 5中重复的has_many记录相关的知识,希望对你有一定的参考价值。
鉴于以下型号:
class Client < ApplicationRecord
has_many :preferences
validates_associated :preferences
accepts_nested_attributes_for :preferences
end
class Preference < ApplicationRecord
belongs_to :client
validates_uniqueness_of :block, scope: [:day, :client_id]
end
在客户端创建期间创建一批首选项时,我仍然可以创建具有重复日期*的首选项。这(看似)是因为运行validates_uniqueness_of
验证时client_id外键不可用。 (*我有一个索引,可以防止复制被保存,但是我想捕获错误,并在它到达数据库之前返回用户友好的错误消息。)
有没有办法通过ActiveRecord验证来防止这种情况发生?
答案
批量插入时,没有一种超级干净的方法可以使用AR验证,但您可以使用以下步骤手动执行此操作。
- 使用Postgresql VALUES列表对数据库进行单个查询以加载任何可能重复的记录。
- 比较您要批量创建和提取任何重复项的记录
- 手动生成并返回错误消息
第1步看起来有点像这样
# Build array of uniq attribute pairs we want to check for
uniq_attrs = new_collection.map do |record|
[
record.day,
record.client_id,
]
end
# santize the values and create a tuple like ('Monday', 5)
values = uniq_attrs.map do |attrs|
safe = attrs.map {|v| ActiveRecord::Base.connection.quote(v)}
"( #{safe.join(",")} )"
end
existing = Preference.where(%{
(day, client_id) in
(#{values.join(",")})
})
# SQL Looks like
# select * from preferences where (day, client_id) in (('Monday',5), ('Tuesday', 3) ....)
然后你可以采取existing
集合并在第2步和第3步中使用它来提取你的副本并生成你的错误消息。
当我需要这个功能时,我通常会把它作为我课堂上的一个自我方法,所以就像这样
class Preference < ApplicationRecord
def self.filter_duplicates(collection)
# blah blah blah from above
non_duplicates = collection.reject do |record|
existing.find do |exist|
exist.duplicate?(record)
end
end
[non_duplicates, existing]
end
def duplicate?(record)
record.day == self.day &&
record.client_id = self.client_id
end
end
以上是关于防止Rails 5中重复的has_many记录的主要内容,如果未能解决你的问题,请参考以下文章
获取 STI 中的记录以获取 rails 4 中的空 has_many 记录