1

モデル内に非常に類似した仮想属性があるという問題に遭遇しました。要するに、それらはいくつかの属性の「コンバーター」として機能しています。これらの仮想属性のいくつかの例を次に示します。

class Setting < ActiveRecord::Base
  validates :overtime, presence: true, numericality: { greater_than_or_equal_to: 0 }
  validates :shift_drop_cut_off, presence: true, numericality: { greater_than_or_equal_to: 0 }

  def overtime_hrs
    return 0 unless self.overtime.present?
    (self.overtime / 3600)
  end

  def overtime_hrs=(overtime_hrs)
    return 0 unless overtime_hrs.present?
    self.overtime = overtime_hrs.to_i * 3600
  end

  def shift_drop_cut_off_hrs
    return 0 unless self.shift_drop_cut_off.present?
    (self.shift_drop_cut_off / 3600)
  end

  def shift_drop_cut_off_hrs=(shift_drop_cut_off_hrs)
    return 0 unless shift_drop_cut_off_hrs.present?
    self.shift_drop_cut_off = shift_drop_cut_off_hrs.to_i * 3600
  end
end

この場合、「overtime」と「shift_drop_cutoff」という名前の 2 つの列があります。これらの列は両方とも、時間を秒単位で表す整数です。ただし、これらの属性を数秒でユーザーに表示したくありません。代わりに、それらを時間に変換したいと思います。したがって、これが仮想属性の目的です。

ご覧のとおり、これらの仮想属性ゲッター/セッターはほぼ同じです。これをリファクタリングする方法についてのヒントはありますか?

4

3 に答える 3

1

メタプログラミング ftw!

module ByHours
  extend ActiveSupport::Concern
  module ClassMethods
    def by_hours(name, base)
      define_method name do
        (send(base) || 0) / 3600
      end
      define_method "#{name}=" do |val|
        send("#{base}=", val * 3600)
      end
    end
  end
end

次に、Setting クラスで次のようにします。

class Setting
  by_hours :overtime_hrs, :overtime
  by_hours :shift_drop_cut_off_hrs, :shift_drop_cut_off
end
于 2014-08-27T16:03:39.747 に答える