在活动模型问题中使用常见的 class 常量名称

Using common class constant name in active model concerns

我希望有多个模型具有共同的货币转换实现和一个共同的常量名称——这里是 PRICE_ATTR

module Priceable
  extend ActiveSupport::Concern

  def value_for(attr, rate)
    (self.send(attr) / rate).round(2)
  end

  PRICE_ATTR.each do |attribute|
    method_name = "#{attribute}_currency".to_sym
    define_method(method_name) do |rate|
      value_for(attribute, rate)
    end
  end
end

class Design
  PRICE_ATTR = [:discount_price, :price]
  include Priceable
end

class Cart
  PRICE_ATTR = [:snapshot_price]
  include Priceable
end

我该怎么做?

您可以像下面这样使用

module Priceable
  extend ActiveSupport::Concern
  included do
    class_variable_set(:@@price_attrs , [])
  end

  module ClassMethods
    def has_prizes(attrs)
      class_variable_set(:@@price_attrs, attrs)
    end
  end

  def value_for(attr, rate)
    (self.send(attr) / rate).round(2)
  end

  class_variable_get(:@@price_attrs).each do |attribute|
    method_name = "#{attribute}_currency".to_sym
    define_method(method_name) do |rate|
      value_for(attribute, rate)
    end
  end
end

class Design
  PRICE_ATTR = [:discount_price, :price]
  include Priceable
  has_prizes PRICE_ATTR
end

class Cart
  PRICE_ATTR = [:snapshot_price]
  include Priceable
  has_prizes PRICE_ATTR

end

或者您可以使用 cattr_accessor 而不是 class_variable_get 和 class_variable_get

这就是 Module#included 的用途!

module Priceable
  extend ActiveSupport::Concern

  def value_for(attr, rate)
    (self.send(attr) / rate).round(2)
  end

  def self.included(othermod)
    othermod::PRICE_ATTR.each do |attribute|
      method_name = "#{attribute}_currency".to_sym
      othermod.send :define_method, method_name do |rate|
        value_for(attribute, rate)
      end
    end
  end
end

class Design
  PRICE_ATTR = [:discount_price, :price]
  include Priceable
end

class Cart
  PRICE_ATTR = [:snapshot_price]
  include Priceable
end

当您将 Priceable 包含到另一个模块(作为参数 othermod 传递)时,它会得到 运行。在该模块中,您可以遍历包含模块的 PRICE_ATTR 数组并在其上定义方法。