1

I want to change the status of few records in a database in the transaction, so I need to throw an exception when the error occurs. Code below is simplified but shows the problem

 User.products.update(status: :vip) # it update but of  didn't throw exception

Following update documentation i tried update! method but it does not work

  User.products.update!(status: :vip) 
  # NoMethodError: undefined method `update!' for #<Product::ActiveRecord_Associations_CollectionProxy:0x00000005463b60

How to use update! method with collection? Should I iterate over all records, and call update! on each record?

Piotr Galas
  • 4,518
  • 2
  • 21
  • 30
  • 1
    As per the [doc](https://apidock.com/rails/ActiveRecord/Base/update/class), `update` should check for validations. Also, for callbacks, please check [this](https://stackoverflow.com/questions/6931812/how-to-update-all-when-you-need-callbacks-fired) post – Abhi Oct 31 '17 at 06:41
  • try using update_all – Sajin Oct 31 '17 at 06:47
  • @Sajin update_all does it does not trigger Active Record callbacks or validations. I need validations. – Piotr Galas Oct 31 '17 at 09:03

1 Answers1

1

You can not update all records within one query and run validations at the same time. You need to iterate over all records and run update! for each of them:

Product.transaction { User.products.each { |pr| pr.update!(status: :vip) } }

Peter Balaban
  • 653
  • 3
  • 7
  • What do you mean one query? Do you mean transaction produce one query to the database, and it is a problem? `update` without `!` run validations on updated records., and produce 2 queries for each record. I want to do the same but with an exception. Code that you suggest will do the job, but it doesn't answer directly. If nobody put better answer I will mark it as answer. – Piotr Galas Oct 31 '17 at 09:01
  • You have tried to call `update!` on the collection, that was a problem. Update on the collection can't run record validations, so you need to call `update!` for each record. For collection you can only run `update_all` or `update`, but they do not run validations, they execute one SQL query. – Peter Balaban Oct 31 '17 at 09:23
  • For collection, you can run both update and update_all. It is not just alias. There are completely different methods. `update` load object and run validations and callback on it but update_all do not. – Piotr Galas Oct 31 '17 at 09:28
  • Yep. You are right. Take a look at the [rails sources](https://github.com/rails/rails/blob/0e8d4edd56f44b27f33bd214aa03af60cc5d39ae/activerecord/lib/active_record/relation.rb#L409), you will see that `update` called there. – Peter Balaban Oct 31 '17 at 09:58