Skip to content

Instantly share code, notes, and snippets.

@willnet
Last active August 7, 2023 02:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save willnet/31a255f66312a41b054ed9b5101cf4e9 to your computer and use it in GitHub Desktop.
Save willnet/31a255f66312a41b054ed9b5101cf4e9 to your computer and use it in GitHub Desktop.
get association models
require 'set'
class InspectAssociations
def self.call(model)
new.call(model)
end
def call(model)
return if set.include?(model)
set.add(model)
model.class.reflections.keys.each do |name|
reflection = model.class.reflections[name]
assoc = model.association(name.to_sym)
if reflection.collection?
children = assoc.reader
children.each { |child| call(child) }
else
child = assoc.reader
call(child) if child
end
end
pp set
end
private
attr_reader :model
def set
@set ||= Set.new
end
end
class InspectSaveChain
class << self
attr_accessor :indent
end
self.indent = 0
def self.call
new.call
end
def initialize
ActiveRecord::Base.descendants.each do |klass|
next if klass.abstract_class
klass.before_save(prepend: true) do |model|
puts "#{' ' * (InspectSaveChain.indent * 2)}#{model.class}#before_save start"
InspectSaveChain.indent += 1
end
klass.before_save do |model|
InspectSaveChain.indent -= 1
puts "#{' ' * (InspectSaveChain.indent * 2)}#{model.class}#before_save end"
end
klass.set_callback(:create, :after) do |model|
puts "#{' ' * (InspectSaveChain.indent * 2)}#{model.class}#after_create start"
InspectSaveChain.indent += 1
end
klass.after_create do |model|
InspectSaveChain.indent -= 1
puts "#{' ' * (InspectSaveChain.indent * 2)}#{model.class}#after_create end"
end
klass.set_callback(:update, :after) do |model|
puts "#{' ' * (InspectSaveChain.indent * 2)}#{model.class}#after_update start"
InspectSaveChain.indent += 1
end
klass.after_update do |model|
InspectSaveChain.indent -= 1
puts "#{' ' * (InspectSaveChain.indent * 2)}#{model.class}#after_update end"
end
end
end
attr_accessor :last_call_method, :last_call_class, :last_return_method, :last_return_class
def autosave_method?(tp)
tp.method_id.match?(/autosave_associated_records_for_/)
end
def save_method?(tp)
tp.method_id == :save || tp.method_id == :save!
end
def duplicate_save_method_call?(tp)
last_call_method == tp.method_id && last_call_class == tp.self.class
end
def duplicate_save_method_return?(tp)
last_return_method == tp.method_id && last_return_class == tp.self.class
end
def autosave_to_save?(tp)
(tp.method_id == :save || tp.method_id == :save!) && last_call_method&.match?(/autosave_associated_records_for_/)
end
def update_last_call(tp)
self.last_call_class = tp.self.class
self.last_call_method = tp.method_id
end
def update_last_return(tp)
self.last_return_class = tp.self.class
self.last_return_method = tp.method_id
end
def call
trace = TracePoint.new(:call, :return) do |tp|
if tp.event == :call
if autosave_method?(tp)
update_last_call(tp)
puts "#{' ' * (self.class.indent * 2)}#{tp.self.class.name}##{tp.method_id} start"
self.class.indent += 1
elsif save_method?(tp) && !duplicate_save_method_call?(tp)
update_last_call(tp)
puts "#{' ' * (self.class.indent * 2)}#{tp.self.class.name}##{tp.method_id} start"
self.class.indent += 1
end
else # :return
if save_method?(tp) && !duplicate_save_method_return?(tp)
self.class.indent -= 1
update_last_return(tp)
puts "#{' ' * (self.class.indent * 2)}#{tp.self.class.name}##{tp.method_id} end"
end
if autosave_method?(tp)
self.class.indent -= 1
puts "#{' ' * (self.class.indent * 2)}#{tp.self.class.name}##{tp.method_id} end"
end
end
end
trace.enable
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment