我遇到了一个问题,我在模型中有非常相似的虚拟属性。简而言之,他们扮演的是转换器"对于某些属性。以下是其中一些虚拟属性的示例:
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
在这种情况下,我有两列名为&#34;加班&#34;和&#34; shift_drop_cutoff&#34;。这两列都是以秒为单位表示时间的整数。但是,我不想在几秒钟内向用户显示这些属性。相反,我想将它们转换成几小时。因此,这是虚拟属性的目的。
正如您所看到的,这些虚拟属性getter / setter几乎完全相同。有没有人有关于如何重构这个的提示?
答案 0 :(得分: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
然后在你的设置课程中:
class Setting
by_hours :overtime_hrs, :overtime
by_hours :shift_drop_cut_off_hrs, :shift_drop_cut_off
end
答案 1 :(得分:1)
您可以定义类处理时间对话并在模型中使用它:
class Duration
attr_reader :hours, :seconds
def self.from_hours(hours)
hours ||= 0
seconds = hours * 3600
new(seconds)
end
def self.from_seconds(seconds)
seconds ||= 0
new(seconds)
end
def initialize(seconds)
@seconds = seconds
@hours = @seconds / 3600
end
end
然后在你的模型中:
def overtime_hrs
Duration.from_seconds(self.overtime).hours
end
def overtime_hrs=(overtime_hrs)
self.overtime = Duration.from_hours(overtime_hrs).seconds
end
def shift_drop_cut_off_hrs
Duration.from_seconds(self.shift_drop_cut_off).hours
end
def shift_drop_cut_off_hrs=(shift_drop_cut_off_hrs)
self.overtime = Duration.from_hours(shift_drop_cut_off_hrs).seconds
end
答案 2 :(得分:0)
尝试对以下方面进行调查: method_missing,define_method并发送ruby。
这是一个很好的tutorial,可以帮助你