Skip to content

Instantly share code, notes, and snippets.

@roychri
Last active December 2, 2016 03:51
Show Gist options
  • Save roychri/29dfe80d7db33ee577fd580d6cdf5b4d to your computer and use it in GitHub Desktop.
Save roychri/29dfe80d7db33ee577fd580d6cdf5b4d to your computer and use it in GitHub Desktop.
Temporary after_destroy rails3 callback using Observers

WARNING

Heavy metaprogramming ahead...

Summary

This is an attempt/experiment at being able to temporarily observe an active record through callbacks.

To Do

Maybe I can have that monkey patched to the ActiveRecord::Base so I could do something like:

Bike.temp_callback(:after_destroy => lambda { |bike| puts "Deleted: #{bike.id}" }) do
  Bike.first.destroy
end
class TemporaryCallback
def self.bind(klass, stalkers)
observers = []
stalkers.each do |callback_name, stalker|
# Our observer needs a name
observer_class_name = "Temporary"+klass.name+callback_name.to_s.camelcase+stalker.object_id.to_s
# Create a new class dynamically (it will be anonymous)
anon_observer_class = Class.new(ActiveRecord::Observer) do
observe klass.name.underscore.to_sym
define_method(callback_name.to_sym) do |record, &block|
puts "record: #{record.inspect}"
if stalker.respond_to?(:call)
puts "calling proc/lambda..."
stalker.call(record, &block)
puts "after calling proc/lambda"
elsif respond_to?(stalker)
send(stalker, record, &block)
elsif klass.respond_to?(stalker)
klass.send(stalker, record, &block)
else
raise "stalker must be a lambda, a proc, a parent method or a method of klass"
end
end
end
# Give a name to the anonymous class
observerClass = Object.const_set(observer_class_name, anon_observer_class)
# Register this new observer once it has a name
observerClass.instance.instance_eval { define_callbacks(klass) }
observers << observerClass
end
yield
# Remove our Observers
observers.each do |observerClass|
ActiveRecord::Base.observers.disable observerClass.name.underscore.to_sym
end
nil
end
end
# Example using Lambda
stalker = lambda { |bike| puts "Deleted: #{bike.id}" }
TemporaryCallback.bind(Bike, :after_destroy => stalker) do
Bike.first.destroy
end
# Example using Proc
stalker = Proc.new { |bike| puts "Deleted: #{bike.id}" }
TemporaryCallback.bind(Bike, :after_destroy => stalker) do
Bike.first.destroy
end
# Example using simple method
def stalker(bike)
puts "Deleted: #{bike.id}"
end
TemporaryCallback.bind(Bike, :after_destroy => :stalker) do
Bike.first.destroy
end
# Example using active record model method
class Bike < ActiveRecord::Base
def self.stalker(bike)
puts "Deleted: #{bike.id}"
end
end
TemporaryCallback.bind(Bike, :after_destroy => :stalker) do
Bike.first.destroy
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment