1

我希望能够使传递给我的类方法(可审计)的选项可用于实例方法。我正在使用模块混合类和实例方法。

显而易见的选择是使用类变量,但在尝试访问它时出现错误:

Auditable 中未初始化的类变量@@auditable_only_once

class Document
  include Auditable
  auditable :only_once => true
end

# The mixin
module Auditable
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def auditable(options = {})

      options[:only_once] ||= false

      class_eval do
        # SET THE OPTION HERE!!
        @@auditable_only_once = options[:only_once]
      end
      end
    end

    private

    def audit(action)
      # AND READ IT BACK LATER HERE
      return if @@auditable_only_once && self.audit_item
      AuditItem.create(:auditable => self, :tag => "#{self.class.to_s}_#{action}".downcase, :user => self.student)
    end    
  end

我已经删除了一些代码以使其更易于阅读,完整的代码在这里:https ://gist.github.com/1004399(编辑:Gist 现在包括解决方案)

4

1 回答 1

0

使用@@类实例变量是不规则的,并且严格要求它们的情况非常少见。大多数时候,它们似乎只是造成麻烦或混乱。通常,您可以在类上下文中使用常规实例变量而不会出现问题。

您可能想要做的是为这类事情使用不同的模板。如果你有mattr_accessorActiveSupport 提供的 ,你可能想要使用它而不是那个变量,或者你总是可以在你的ClassMethods组件中编写你自己的等价物。

我使用的一种方法是将扩展分解为两个模块,一个钩子和一个实现。该钩子仅将方法添加到可用于在需要时添加其余方法的基类,但不会污染命名空间:

module ClassExtender
  def self.included(base)
    base.send(:extend, self)
  end

  def engage(options = { })
    extend ClassExtenderMethods::ClassMethods
    include ClassExtenderMethods::InstanceMethods

    self.class_extender_options.merge!(options)
  end
end

这个engage方法可以被称为任何你喜欢的,就像在你的例子中一样auditable

接下来,为扩展在执行时添加的类和实例方法创建一个容器模块:

module ClassExtenderMethods
  module ClassMethods
    def class_extender_options
      @class_extender_options ||= {
        :default_false => false
      }
    end
  end

  module InstanceMethods
    def instance_method_example
      :example
    end
  end
end

在这种情况下,有一个简单的方法class_extender_options可用于查询或修改特定类的选项。这避免了必须直接使用实例变量。还添加了一个示例实例方法。

你可以定义一个简单的例子:

class Foo
  include ClassExtender

  engage(:true => true)
end

然后测试它是否正常工作:

Foo.class_extender_options
# => {:default_false=>false, :true=>true}

foo = Foo.new
foo.instance_method_example
# => :example
于 2011-06-02T15:37:45.883 回答