Last Updated: February 25, 2016
·
1.975K
· tjbladez

Prevent unnecessary chained touches in Rails

In a lot of cases (cache invalidation mostly) touch true is a valid solution. However, current Rails touch: true chaining is over aggressive and it is possible that same record(s) will be touched multiple times or unnecessary. This quick hack will prevent that touching molestation. Takes a block within which it will limit record(s) to be touched only once.

class Disturbed
  class << self
    attr_accessor :records
  end

  def self.records
    @records || Set.new
  end

  def self.add_record(record)
    @records ||= Set.new
    @records.add(record)
  end

  def self.clear_records
    @records.clear
  end
end

module DisturbedRecord
  include ActiveSupport::Concern

  def disturb
    Disturbed.add_record(self)
  end
end

module DisturbedAction
  include ActiveSupport::Concern

  def disturbed
    begin
      ActiveRecord::Base.send(:alias_method,:old_touch, :touch)
      ActiveRecord::Base.send(:alias_method,:touch, :disturb)
      yield
    rescue Exception => e
      raise e
    ensure
      Disturbed.records.each {|r| r.old_touch }
      Disturbed.clear_records
      ActiveRecord::Base.send(:alias_method, :touch, :old_touch)
      ActiveRecord::Base.send(:remove_method,:old_touch)
    end
  end
end

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

3 Responses
Add your response

This looks like exactly what I need, but I'm not sure I understand if this is supposed to work automatically or I need to wrap my update code with a wrapper. Please let me know.

over 1 year ago ·

It doesn't work automatically, you need to to wrap your code in the disturbed block like this:

disturbed do
   #your code goes here
   Purchase.register(current_user, params) #for example
end

Let me know if that works, I can throw you some examples in the live app as well.

over 1 year ago ·

This is great, thanks for the post. However it would be nice if we could get the core issue with current :touch implementation fixed.

Ticket for it appears to be here' https://github.com/rails/rails/issues/8759#issuecomment-49540505

It's been closed which is frustrating.

over 1 year ago ·