Skip to content

Instantly share code, notes, and snippets.

@iagopiimenta
Created October 30, 2016 23:03
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 iagopiimenta/8c936fa8cd968fa0c11b258695f80e88 to your computer and use it in GitHub Desktop.
Save iagopiimenta/8c936fa8cd968fa0c11b258695f80e88 to your computer and use it in GitHub Desktop.
Mongoid 3.1.6 - Rails 3.2 - accessed_fields
# lib/accessed_fields.rb
module AccessedFields
def self.included(klass)
klass.extend(ClassMethods)
return unless klass.respond_to?(:fields)
klass.fields.keys.each do |field_name|
klass.wrap_default_method(field_name)
end
klass.class_eval do
alias_method :id, :_id
alias_method :id=, :_id=
end
end
def accessed_fields
accessed_fields_history.map do |field_info|
field_info[0]
end.uniq
end
def accessed_fields_history
@accessed_fields_history ||= []
end
module ClassMethods
def field(*args)
super(*args)
wrap_default_method(args[0])
end
def wrap_default_method(method)
mod = Module.new
mod.class_eval do
define_method(method) do
__register_call(method.to_s)
super()
end
define_method("#{method}=") do |value|
__register_call(method.to_s)
super(value)
end
private
def __register_call(field)
backtrace = Rails.backtrace_cleaner.clean(caller)
accessed_fields_history << [
field,
backtrace[1..-1],
Time.current.to_f
]
end
end
prepend mod
end
end
end
# lib/afm.rb
# Based on https://gist.github.com/kddeisz/64a976d73ad44edf1d9fbf529b9f780e
require 'logger'
module Afm
class Railtie < Rails::Railtie
initializer 'afm.action_controller' do
ActiveSupport.on_load(:action_controller) do
include ControllerExtensions
end
end
end
module ControllerExtensions
Result = Struct.new(:class_name, :accessed, :unused, :history) do
def to_log
@to_log ||= "#{class_name}:\n Unused: #{unused.sort.join(', ')}\n Used: #{accessed.sort.join(', ')}\n #{backtrace}\n"
end
def backtrace
history.map do |field_info|
"\n " + field_info[0..1].join("\n ")
end.join("\n ")
end
end
def self.included(base)
base.after_filter :report_accessed_fields
end
private
def report_accessed_fields
found = []
Afm.registry.each do |record|
accessed = record.accessed_fields
history = record.accessed_fields_history
unused = (record.attributes.keys - accessed)
next if unused.empty?
found << Result.new(record.class.name, accessed, unused, history)
end
if found.any?
Afm.logger.info("#{controller_name}##{action_name}")
found.sort_by(&:to_log).each { |result| Afm.logger.info(" #{result.to_log}") }
Afm.logger.info("\n")
end
ensure
Afm.clear_registry
end
end
module ModelExtensions
def self.included(base)
base.after_initialize :register_in_afm
end
private
def register_in_afm
Afm.register(self)
end
end
class << self
def clear_registry
@registry = nil
end
def logger
@logger ||= Logger.new(Rails.root.join('log', 'afm.log'))
end
def register(record)
registry << record
end
def registry
@registry ||= []
end
end
end
# on application.rb :
# # require File.expand_path('../../lib/afm', __FILE__)
# config/initializers/mongoid_initializer.rb
require_dependency 'accessed_fields'
module Mongoid
alias __original_register_model register_model
def register_model(klass)
__original_register_model(klass)
klass.include AccessedFields
klass.include Afm::ModelExtensions
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment