Rails Suppressor Pattern
While grokking through Rails source code, one pattern caught my eye, namely Suppressor.
Here is the full listing, and as you could spot, it’s quite concise.
But, I spent some time trying to figure out how it works in the context of ActiveRecord. How does it suppress callbacks and notifications?
Honestly, it took me a while to figure out. Give yourselve several minutes to read through the code. It’s really there!
module ActiveRecord
module Suppressor
extend ActiveSupport::Concern
class << self
def registry # :nodoc:
ActiveSupport::IsolatedExecutionState[:active_record_suppressor_registry] ||= {}
end
end
module ClassMethods
def suppress(&block)
previous_state = Suppressor.registry[name]
Suppressor.registry[name] = true
yield
ensure
Suppressor.registry[name] = previous_state
end
end
def save(**) # :nodoc:
Suppressor.registry[self.class.name] ? true : super
end
def save!(**) # :nodoc:
Suppressor.registry[self.class.name] ? true : super
end
end
end
How smart! I thought after discovery.
Turns out, when this class is included in ActiveRecord, it replaces save
method of the instance with this implementation from above, that either returns true
and skips the execution or calls super
method, which, I’m sure, should be available in the execution stack.
Inspired by this I was able to quickly implement the same idea in my code, responsible for suppression of the Notifications delivery class, which was just PORO.
Final thouhts, how often we ignore wisdom of others lying right under the feets? Just read the beautiful code we all already have!