编写活动装饰器DRY

时间:2019-07-02 03:24:03

标签: ruby-on-rails ruby datetime rubygems decorator

我正在使用ActiveDecorator:https://github.com/amatsuda/active_decorator

在编写UserDecorator时,我发现它有很多重叠之处。只是装饰datetime,但我不得不重复写很多装饰器。

# frozen_string_literal: true

module UserDecorator
  def created_at_datetime
    created_at&.strftime '%Y/%m/%d %H:%M:%S'
  end

  def confirmed_at_datetime
    confirmed_at&.strftime '%Y/%m/%d %H:%M:%S'
  end

  def locked_at_datetime
    locked_at&.strftime '%Y/%m/%d %H:%M:%S'
  end

  def current_sign_in_at_datetime
    current_sign_in_at&.strftime '%Y/%m/%d %H:%M:%S'
  end

  def last_sign_in_at_datetime
    last_sign_in_at&.strftime '%Y/%m/%d %H:%M:%S'
  end
end

猜猜我的AdminDecorator上的字段完全相同。我是否必须将所有这些都再次复制到AdminDecorator? 有什么建议吗?

参考:https://github.com/amatsuda/active_decorator/issues/104

3 个答案:

答案 0 :(得分:5)

我不使用active_decorator,但我想创建一个DatetimeDecorator,就像这样:

module DatetimeDecorator

  %i(
    created_at
    confirmed_at
    locked_at
    current_sign_in_at
    last_sign_in_at
  ).each do |attr_sym|
    define_method("#{attr_sym}_datetime") do 
      send(attr_sym)&.strftime '%Y/%m/%m %H:%M:%S'
    end
  end

end

无论何时包含此模块,都将获得先前在UserDecorator中定义的五个方法,每个方法都使用相同的格式代码。

现在,要包含该模块,请使用included钩子。像这样:

module UserDecorator

  self.included(base)
    base.class_eval do 
      include DatetimeDecorator
    end
  end

end

module AdminDecorator

  self.included(base)
    base.class_eval do 
      include DatetimeDecorator
    end
  end

end

现在,您的UserDecoratorAdminDecorator都具有您先前在UserDecorator中定义的五种方法。

这是未经测试的,因此您可能需要摆弄一下。

答案 1 :(得分:2)

这与jvillian's answertruongnm's answer非常相似。

我通常会写一些DSL方法来添加重复方法,如下所示:

async

await是一个类方法,它基于给定的参数定义一个实例方法。将module DateFormatter DEFAULT_FORMAT = '%Y/%m/%d %H:%M:%S' def add_formatter(attribute, format: DEFAULT_FORMAT) define_method("#{attribute}_datetime") do public_send(attribute)&.strftime(format) end end end 作为可选参数只是一个例子。

作为类方法,可以像这样在类体内直接调用add_formatter

format

add_format模块最终具有各种新方法:

module UserDecorator
  extend DateFormatter

  add_formatter :created_at
  add_formatter :confirmed_at, format: '%A %-d, %Y'
  add_formatter :locked_at
  add_formatter :current_sign_in_at
  add_formatter :last_sign_in_at
end

可以像往常一样调用它们:

UserDecorator

由于使用的是Rails,因此您可能希望合并其ActiveSupport::Concern模式。

答案 2 :(得分:1)

我可以使用类似这样的元代码,但是我无法在"Vertical"处解决完全相同的字段。这意味着我仍然需要将下面的粘贴功能复制到AdminDecorator

AdminDecorator

这将创建方法是否接受参数格式:

module UserDecorator
  DATETIME_DECORATOR_FIELDS = %w[created_at confirmed_at locked_at current_sign_in last_sign_in_at].freeze

  DATETIME_DECORATOR_FIELDS.each do |field|
    define_method("#{field}_datetime") do |format = nil|
      return send(field)&.strftime(format) if format

      send(field)&.strftime '%Y/%m/%m %H:%M:%S'
    end
  end
end