所以我在我的Rails应用程序上有一个模型,里面有一个名字字段。在数据库中,此字段具有针对它设置的唯一约束。
在模型级别,我也在进行uniqueness: { case_sensitive: false }, on: :create
检查。
我的想法是,在ActiveRecord验证完成后,如果唯一性检查失败,那么我想为同一个表中的所有就绪现有记录增加一个计数器。所以我现在所做的就是:
after_validation :term_exists
private
def term_exists
if self.errors.added? :name, :taken
Term.where('LOWER(name) = LOWER(?)', self[:name]).update_all('popularity_counter = popularity_counter + 1')
end
end
这会很棒但是当我对它进行测试时,计数器永远不会增加。我想这样做的原因是,一旦事实证明验证失败,该事务中的所有内容都将被回滚。
那么解决这类问题的轨道方法是什么呢?强烈建议不要将这种逻辑保留在控制器中。
答案 0 :(得分:1)
如果您使用MySQL,则可以尝试INSERT ... ON DUPLICATE KEY UPDATE ...
(请参阅the docs)。为此,您必须为name
列添加唯一索引。在这种情况下,您不需要任何唯一性验证。
还有一个名为upsert
的有希望的宝石(这是“更新而不是插入”的常用首字母缩写词)但它还不支持更新不同的列(例如计数器)而不是插入的值。您可以观看this issue。
答案 1 :(得分:1)
我会说您需要创建自定义的before_validation方法,您可以在其中检查名称是否唯一,如果没有,则更新您的计数器,然后验证失败。
在这种情况下,您可以删除Rails uniqueness: { case_sensitive: false }, on: :create
,因为它显然无法执行您想要的操作。
我认为这将是我脑海中最干净的方式。