aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/suppressor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/suppressor.rb')
-rw-r--r--activerecord/lib/active_record/suppressor.rb55
1 files changed, 55 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/suppressor.rb b/activerecord/lib/active_record/suppressor.rb
new file mode 100644
index 0000000000..b0b86865fd
--- /dev/null
+++ b/activerecord/lib/active_record/suppressor.rb
@@ -0,0 +1,55 @@
+module ActiveRecord
+ # ActiveRecord::Suppressor prevents the receiver from being saved during
+ # a given block.
+ #
+ # For example, here's a pattern of creating notifications when new comments
+ # are posted. (The notification may in turn trigger an email, a push
+ # notification, or just appear in the UI somewhere):
+ #
+ # class Comment < ActiveRecord::Base
+ # belongs_to :commentable, polymorphic: true
+ # after_create -> { Notification.create! comment: self,
+ # recipients: commentable.recipients }
+ # end
+ #
+ # That's what you want the bulk of the time. New comment creates a new
+ # Notification. But there may well be off cases, like copying a commentable
+ # and its comments, where you don't want that. So you'd have a concern
+ # something like this:
+ #
+ # module Copyable
+ # def copy_to(destination)
+ # Notification.suppress do
+ # # Copy logic that creates new comments that we do not want
+ # # triggering notifications.
+ # end
+ # end
+ # end
+ module Suppressor
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def suppress(&block)
+ SuppressorRegistry.suppressed[name] = true
+ yield
+ ensure
+ SuppressorRegistry.suppressed[name] = false
+ end
+ end
+
+ # Ignore saving events if we're in suppression mode.
+ def save!(*args) # :nodoc:
+ SuppressorRegistry.suppressed[self.class.name] ? true : super
+ end
+ end
+
+ class SuppressorRegistry # :nodoc:
+ extend ActiveSupport::PerThreadRegistry
+
+ attr_reader :suppressed
+
+ def initialize
+ @suppressed = {}
+ end
+ end
+end