【发布时间】:2015-10-14 16:59:29
【问题描述】:
我正在使用存储温度值的 Rails/Angular 应用程序。温度始终以摄氏度存储在数据库中。这些温度值可以根据用户的偏好以摄氏度或华氏度显示给用户。
如果温度达到某个值,该应用程序还可以提醒用户。这很重要,因为用户可能会以华氏温度输入警报值,但需要先将其转换为摄氏温度,然后才能将其存储到数据库中。这些alert 值也位于与温度读数本身不同的表中,因此该解决方案非常适用于各种型号。
因此,从本质上讲,我需要找到最佳位置和策略,以便在读取并保存到数据库中的值。我们尝试了几种不同的方法,但我希望将它们重构为一个很好的可维护解决方案,其中包含尽可能少的代码路径。
对于温度读数的显示时间变化,我们在ReadingsController 中使用了控制器问题。如果用户有此偏好,则映射到将转换为华氏温度的 ReadingPresenter。
class ReadingPresenter
include ApplicationHelper
def initialize(sensor_reading, sample_type)
@model = sensor_reading
@sample_type = sample_type
end
def value
if @sample_type.temperature?
TemperatureService.for_current_user @model.value
else
@model.value
end
end
end
当我们需要显示已经存储的华氏温度读数时,这可以正常工作,但是由于它是演示者,因此当我们需要将用户输入的华氏温度 alert 值更改为摄氏温度以存储在数据库。
在这种情况下,我们创建了一个模型关注点,它有 before_save、after_save 和 after_find 回调来操作。
module TemperatureAttributes
extend ActiveSupport::Concern
module ClassMethods
def temperatures(*temperature_attributes)
options = temperature_attributes.extract_options!
before_save TemperatureScaleConverter.new(temperature_attributes, options[:if])
after_save TemperatureScaleConverter.new(temperature_attributes, options[:if])
after_find TemperatureScaleConverter.new(temperature_attributes, options[:if])
end
end
end
这确实有效,但您可以看到它是完全不同的代码路径。我不得不想象在 Rails 中有更好的方法来处理这种情况。
我一直在尝试使用Ruby's prepend method 来拦截呼叫,并且还考虑过以类似的方式使用alias_method_chain。我还考虑过尝试有条件地使用数据库视图来尽可能地转换最低级别的值。
我不是在找你来帮我解决我的问题,但是如果你对在 Rails 中跨模型拦截 getter 和 setter 调用的最佳方法有任何建议,我很想听听.
【问题讨论】:
标签: ruby-on-rails ruby