Search code examples
ruby-on-railsblock

Disable touch for the duration of a block in ActiveRecord


I have a deep cloning process in my rails app, as well as a recursive deletion process that deletes the node of a tree and its descendants and their associations. Both of these routines have problems when :touch => true is applied to the relationships. It's fine when we're just updating one record to have the change touch all the parent records up the associations and tree structure, but when we're dealing with bulk creation or deletion it makes sense to disable touching for the duration of that call.

I'm looking for direction around how I'd define a method that accepts a block for running code that would not activate the touch method on objects.

I'm thinking perhaps just before yielding I should set a global? variable that indicates touching is disabled, and then override the touch method to first check for this variable before calling super (or not as the case may be).

Any help to solidify this into actual code would be appreciated. :)


Solution

  • In Rails 4.1 or later you can use the ActiveRecord no_touching method to prevent touching in a single model or in all models like this:

    ActiveRecord::Base.no_touching do
      Project.first.touch  # does nothing
      Message.first.touch  # does nothing
    end
    
    Project.no_touching do
      Project.first.touch  # does nothing
      Message.first.touch  # works, but does not touch the associated project
    end