使ActiveRecord :: Base方法的所有子类都说出他们的名字

时间:2010-03-10 19:08:28

标签: ruby-on-rails ruby activerecord

出于移除目的,我想记录一个来自我的AR模型的方法。

我可以通过以下方式获得所有这些课程:

subclasses = [] ; ObjectSpace.each_object(Module) {|m| subclasses << m if m.ancestors.include? ActiveRecord::Base } ; subclasses.map(&:name)

但是我需要一个只列出在这些类上定义的方法的列表(实例和类方法),以及在其中注入logger语句的方法。

结果相当于将其插入到每个方法

def foo
  logger.info "#{class.name} - #{__method__}"
  # ...
end

def self.foo
  logger.info  "#{name} - #{__method__}"
  # ...
end

如果不将其实际添加到每个方法中,我该怎么做?

也许有些可怕的元?

5 个答案:

答案 0 :(得分:1)

如果您只想要在课程中定义的方法,您可以这样做:

>> Project.instance_methods
=> ["const_get", "validates_associated", "before_destroy_callback_chain", "reset_mocha", "parent_name", "inspect", "slug_normalizer_block", "set_sequence_name", "require_library_or_gem", "method_exists?", "valid_keys_for_has_and_belongs_to_many_association=", "table_name=", "validate_find_options_without_friendly", "quoted_table_name" (another 100 or so methods)]

仅限您班级中定义的方法

>> Project.instance_methods(false)
=> ["featured_asset", "category_list", "before_save_associated_records_for_slugs", "asset_ids", "primary_asset", "friendly_id_options", "description", "description_plain"]

答案 1 :(得分:1)

您应该使用面向方面编程模式。在Ruby Aquarium gem中提供了AOP DSL。

log_method_initializer.rb目录中创建config/initializers/

require 'aquarium'
Aspect.new(:around, :calls_to => :all_methods, 
            :in_types => [ActiveRecord::Base] ) do |join_point, object, *args|

  log "Entering: #{join_point.target_type.name}##{join_point.method_name}" 

  result = join_point.proceed

  log "Leaving: #{join_point.target_type.name}##{join_point.method_name}" 

  result  
end

将记录从ActiveRecord::Base继承的类的每个方法调用。

答案 2 :(得分:0)

你有

AR :: Base.instance_methods

和 AR :: Base.class_eval“some string”

因此您可以使用它们在每个现有方法上添加标题。

答案 3 :(得分:0)

例如,方法调用可以使用此代理模式:

class BlankSlate
   instance_methods.each { |m| undef_method m unless m =~ /^__/ }
end

class MyProxy < BlankSlate
  def initialize(obj, &proc)
    @proc = proc
    @obj = obj
  end

  def method_missing(sym, *args, &block)
    @proc.call(@obj,sym, *args)
    @obj.__send__(sym, *args, &block)
  end
end

示例:

cust = Customer.first
cust = MyProxy.new(cust) do |obj, method_name, *args|
  ActiveRecord::Base.logger.info  "#{obj.class}##{method_name}"
end

cust.city

# This will log:
# Customer#city

灵感来自:http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc

您需要找到一种方法在ActiveRecord :: Base对象创建上应用此模式。

答案 4 :(得分:0)

对于水族馆来说,似乎添加method_options => :exclude_ancestor_methods就可以了。 我的堆栈问题太深了。

来源 http://andrzejonsoftware.blogspot.com/2011/08/tracing-aspect-for-rails-application.html