如果验证失败,如何不回滚ActiveRecord事务

时间:2016-06-15 19:47:41

标签: ruby-on-rails activerecord

所以我在我的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

这会很棒但是当我对它进行测试时,计数器永远不会增加。我想这样做的原因是,一旦事实证明验证失败,该事务中的所有内容都将被回滚。

那么解决这类问题的轨道方法是什么呢?强烈建议不要将这种逻辑保留在控制器中。

2 个答案:

答案 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,因为它显然无法执行您想要的操作。

我认为这将是我脑海中最干净的方式。