Last active
March 5, 2018 17:26
-
-
Save cluesque/08da6f4d0e24eea47eb9da8b73b5841d to your computer and use it in GitHub Desktop.
Suppressible mixin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DHH's On Writing Software (well?) [episode 2](https://www.youtube.com/watch?v=m1jOWu7woKM) discussed callbacks, specifically the practice of hiding side effects of object creation using `after_save` and `after_commit` hooks. | |
It implicitly conceeded that `after_commit`, lacking information about what was just committed, was flawed, and uses the common workaround of using an `after_save` to decide to do something based on changes and set an @ivar, and then in the `after_commit` acting on the @ivar found. Which is fun, but. | |
It also [at the end](https://youtu.be/m1jOWu7woKM?t=1151) discussed the possibility that in some use cases a caller might want to explicitly prevent side effects from happening. Think about when audited temporarily suppresses auditing, or perhaps one might want to bulk update some data, without sending the email normally sent when said data is updated. | |
It teased the presence of a `Suppressible` mixin. For fun, I wrote it. | |
Update: turns out the real one is public. It uses `thread_mattr_accessor` and `Module#extended` and is therefore much better. | |
https://gist.github.com/thechrisoshow/2c10bf4530528588453b4f8a6d8763fb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> Narf.new.do_stuff | |
Doing Stuff! | |
=> nil | |
> Narf.suppress{ Narf.new.do_stuff } | |
=> nil |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Narf | |
include Suppressible | |
def do_stuff | |
puts "Doing Stuff!" unless suppressed? | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Suppressible | |
extend ActiveSupport::Concern | |
# Supports the notion that some activities on a class | |
# might have some side effects and that those side effects | |
# might want to be temporarily suppressed by some calling code | |
# Useful, e.g., where an `after_save` callback sends email, | |
# but some bulk update wants to suppress said email | |
# class Widget < ActiveRecord::Base | |
# after_commit :send_creation_notice | |
# | |
# def send_creation_notice | |
# WidgetAnnouncer.announce self | |
# end | |
# end | |
# | |
# class WidgetAnnouncer | |
# include Suppressible | |
# def announce(widget) | |
# send_widget_email(widget) unless suppressed? | |
# end | |
# end | |
# Now, when you want to make a bunch of widgets and later send a bulk announcement: | |
# WidgetAnnouncer.suppress do | |
# 100.times do | |
# Widget.create | |
# end | |
# end | |
# send_bulk_widget_announcement | |
def suppress &block | |
self.class.suppress block | |
end | |
def suppressed? | |
self.class.suppressed? | |
end | |
module ClassMethods | |
def suppress &block | |
previous = suppressed? | |
begin | |
self.suppressed = true | |
yield | |
ensure | |
self.suppressed = previous | |
end | |
end | |
def suppressed=(value) | |
Thread.current["#{name.tableize}_suppressed"] = value | |
end | |
def suppressed? | |
!!Thread.current["#{name.tableize}_suppressed"] | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment