简体   繁体   中英

How to not rollback a ActiveRecord transaction in case of failed validation

So I have a Model on my Rails app that has a name field in it. In the database this field has a unique constraint set against it. In the model level I am also doing a uniqueness: { case_sensitive: false }, on: :create check.

My idea is that, after the ActiveRecord validations are done and if the uniqueness check failed then I want to increment a counter for the all ready existing record in the same table. So what I do right now is this:

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

This would be great but when I run my tests against it, the counter never gets incremented. I imagine that the reason for this is that everything in that transaction will be rolled back once it turns out the validations failed.

But what would be the rails way to solve this kind of problem then? It is strongly advised not to keep such logic in controllers.

If you use MySQL, you could instead try INSERT ... ON DUPLICATE KEY UPDATE ... (see the docs ). For this to work you would have to add a unique index for the name column though. You would not need any uniqueness validation in this scenario.

There is also a promising gem called upsert (which is a commonly used acronym for "update instead of insert") but it does not yet support updating a different column (eg a counter) instead of the inserted values. You can watch this issue though.

I would say that you need to create your custom before_validation method where you can check whether the name is unique and if not then update your counter and then fail validation.

In this case you can remove Rails uniqueness: { case_sensitive: false }, on: :create because it clearly does not do what you want.

I think it would be the cleanest way that comes to my mind.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM