我有一个作者模型和一本书模型。
一个作者可以有很多书,一本书也可以有很多作者。因此,它们通过第三个模型AuthorBook链接。
该模型有三个字段:author_id,book_id,还有:角色
Roles是一个jsonB数组,其中包含作者在本书中的角色。它可以是例如“main_author”、“corrector”、“translator”等。作者可以具有1个、多个或所有角色。
我想要一个AuthorBook,对于一本给定的书,只允许一个作者有一定的角色。只能有一个“main_author”、“corrector”等。
我试着实现一个验证,比如这个:
class AuthorBook < ApplicationRecord
validate :uniqueness_of_author_role_for_book
def uniqueness_of_author_role_for_book
others_records = AuthorBook.where(book_id:).where.not(user_id:)
return if others_records.blank?
other_records.each do |record|
errors.add(:roles, "#{record.roles.join(',')} already exists on another user") if roles_already_assigned?(record)
end
end
private
def roles_already_assigned?(record)
roles.map(&:to_s).intersect?(record.roles)
end
end
可悲的是,有一个边缘情况下,这不工作。
如果我将AuthorBook的作者从author 1更新为author 2,具有相同的角色;这段代码将检测author 1的存在,author 1有一本书的AuthorBook,具有相同角色,验证将失败。
它不应该失败,因为在更新之后,author 1将不再具有该角色,并且它应该是有效的。
可能有更好的方法来做到这一点,但我似乎不能指出它。
1条答案
按热度按时间fquxozlt1#
另一种方法是为每个角色设置一条
AuthorBook
记录,而不是数组列。然后,您可以简单地在book_id
上使用标准的唯一性验证