Activerecord: преобразование строк во времена по местному времени

#activerecord #timezone

#activerecord #Часовой пояс

Вопрос:

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

 Time.zone
=> GMT-05:00 Eastern Time US  Canada

t = Ticket.first
t.hold_until = "Jan 1, 2012 9:00PM"
t.save!

t.hold_until
=> Sun, 01 Jan 2012 16:00:00 EST -05:00

# notice the above time lost 5 hours
  

Проблема в том, что строка взята из POST-запроса, предоставленного пользователем. Не разумнее ли предположить, что пользовательский ввод осуществляется по их местному времени, а не по UTC. Я что-то упускаю или это не должно быть значением ActiveRecord по умолчанию? Каков правильный способ сделать это, помимо необходимости конвертировать время во всех моих контроллерах. Это просто кажется неправильным и не очень СУХИМ.

Ответ №1:

Я разобрался с проблемой, и она связана с плохо написанным кодом в ActiveRecord (сюрприз!). В любом случае, ActiveRecord::Base.define_attribute_methods вызывается лениво из-за отсутствия метода. У меня этот метод был определен следующим образом:

 def hold_until=(value)
  # do some stuff here
  super
end
  

Итак, ActiveRecord пропускал этот метод, думая, что он был определен. Это не должно иметь значения, но из-за плохого дизайна это имеет значение. В AR есть множество различных способов определения методов на основе их типа столбца. Вызов super side выполняет это и переходит прямо к общему вызову «write_attribute». Единственное решение — преобразовать время самостоятельно. Вы не можете вызвать define_attribute_methods перед включением модулей из-за всей этой ерунды с alias_method_chain. И вы не можете использовать код, который они уже написали, потому что он находится в блоке class_eval. Я бы рекомендовал datamapper, если это вообще возможно.