My Task model has commit callbacks that send notifications. But the task model ALSO gets touched by a bunch of associated/child records, and these really shouldn’t be sending notifications for each one.

I’ve decided to write a simple touch_without_callbacks method that helped me acheive this.

How to touch rails columns without callbacks

create an initializer called touch_without_callbacks.rb

module TouchWithoutCallbacks
  extend ActiveSupport::Concern

  def touch_without_callbacks(*names, time: nil)
    time ||= current_time_from_proper_timezone

    attribute_names = timestamp_attributes_for_update_in_model
    attribute_names |= names.map(&:to_s)

    return false if attribute_names.empty?

    changes = {}

    attribute_names.each do |attr_name|
      changes[attr_name] = time
    end

    primary_key = self.class.primary_key
    self.class.unscoped
              .where(primary_key => self[primary_key])
              .update_all(changes) == 1
  end

  def current_time_from_proper_timezone
    default_timezone == :utc ? Time.now.utc : Time.now
  end
end

# include the extension into your rails models

ActiveRecord::Base.send(:include, TouchWithoutCallbacks)

So now in your rails code, you can do something like this:

task = Task.find(...)
task.touch_without_callbacks # will change the `updated_at`
                             # will not trigger callbacks

task.touch_without_callbacks(:reminder_at)
                      # will change both `updated_at` and `reminder_at`
                      # will not trigger callbacks

Docs on #touch: