鉴于以下模型:
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验证来防止这种情况发生?
答案 0 :(得分:1)
批量插入时,使用AR验证没有超级干净的方法,但您可以通过以下步骤手动完成此操作。
第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