2015-10-14 5 views
0

Я работаю с Rails/угловым приложением, которое сохраняет значения температуры. Температуры всегда хранятся в градусах Цельсия в базе данных. Эти значения температуры могут отображаться пользователю в градусах Цельсия или Фаренгейта, исходя из предпочтений пользователя.Перехват вызовов приемника и сеттера в Rails для обработки данных

Приложение может также предупредить пользователя, если температура достигает определенного значения. Это важно, потому что пользователь может ввести значение предупреждения в Fahrenheit, но его необходимо преобразовать в цельсию до его сохранения в базе данных. Эти значения alert также находятся в другой таблице, чем сами показания температуры, поэтому решение идеально подходит для разных моделей.

Таким образом, по существу, мне нужно найти лучшее место и стратегию для управления значением, когда они считываются и сохраняются в базу данных. Мы пробовали пару разных вещей, но я стараюсь реорганизовать их в удобное поддерживаемое решение, которое включает в себя как можно меньше кодовых путей.

Для отображения показаний температуры в режиме отображения мы использовали проблему с контроллером в ReadingsController. Это сопоставляется с ReadingPresenter, который будет конвертировать в Fahrenheit, если пользователь имеет это предпочтение.

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 

Это прекрасно работает, когда нам нужно отобразить чтение Fahrenheit, который уже хранится, но так как это ведущий он явно не будет работать, когда нам нужно изменить введенное пользователем значение Фаренгейта 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. Я также думал о попытке условно использовать представления базы данных для преобразования значений на самом низком уровне.

Я не ищу, чтобы вы разрешили мою проблему для меня, но , если у вас есть какие-либо советы по наилучшему способу перехвата вызовов getter и setter в Rails по моделям Мне бы очень хотелось его услышать.

ответ

0

Я думаю, что вы делаете некоторые вещи более сложными, чем они должны быть, а также намекая на использование некоторых приятных шаблонов.

Первый выпуск ваше использование обратных вызовов ... Я думаю, что вы хотите использовать after_initialize ...

class ReadingPresenter 
     ... 
     after_initialize :presentation_value 

     def presentation_value 
      TemperatureService.for_current_user @model.value 
     end 

И затем использовать этот presentation_value вместо значения. (Я предполагаю, что есть хорошая причина иметь класс ReadingPresenter, а не просто работать с какой-то моделью, такой как Температура < ActiveRecord :: Base).

Я думаю, что вы, вероятно, принимаете правильное решение использовать службу для обработки значения презентации, тем более, что я могу себе представить, что привлекает статус из других частей вашего приложения.Я также думаю, что большая часть вашей логики в обратных вызовах находится рядом, и ее лучше обрабатывать, используя что-то вроде after_initialize. Но также странно, что вы не просто управляете презентацией объекта «Температура», вы можете обрабатывать немного более атомарно, чем обрабатывать презентацию как «вещь» для себя.

+0

Спасибо, что нашли время ответить - я ценю это. Мне нравится использование 'after_initialize' в объекте Presenter. Я об этом не думал. Если я не понимаю, я не мог использовать блок 'after_initialize', чтобы помочь с ** установкой ** значения в градусах Цельсия, когда передается значение Фаренгейта, правильно? – JackCollins

+0

Это немного сложно ответить, не видя всей базы кода, и мой ответ неясен в результате. Я думаю, что вы правы, но я думаю, что многие проблемы уходят, если вы используете температуру jjk

Смежные вопросы