我有一个Event
模型的编辑视图,其中包含name
、start_time
和end_time
字段。我的观点是一个大致看起来像这样的形式:
# ...
# form with:
# - event name
# - datetime_select for event start_time (in business's local time zone)
# - datetime_select for event end_time (in business's local time zone)
现在,问题来了:start_time
和end_time
附加了一个时区,但是当我们渲染视图时,该时间会丢失,因为datetime_select不包含时区字段。结果是,我们有一个"UTC时间",它实际上是从其时区中剥离的本地时间。
回顾一下,当我们在视图中呈现表单时,情况如下所示,然后立即提交而不进行任何更改:
db time: 2011-05-15 @ 1100 UTC
converted to local time: 2011-05-15 @ 0600 CDT
time stored in view: 2011-05-15 @ 0600 UTC (time zone info lost)
time posted back to db: 2011-05-15 @ 0600 UTC
请注意,存储的时间最初是 1100 UTC,但现在是 0600 UTC,即使我们没有进行任何更改。这是一个严重的错误。
我们可以在这里采取多种方法。在发布到视图时避免丢失时区的最聪明方法是什么?(请注意,模型可能会以发布表单以外的方式进行更新 - 例如,通过 API。
感觉从来都不是很令人满意,但我通常通过为名为 local_time 或 time_formatted 或类似内容的虚拟属性制作一些新方法来解决这个问题,这些方法从存储在数据库中的 UTC 时间来回转换。
在此示例中,db 字段为"deadline",虚拟属性为"deadline_formatted":
def deadline_formatted
self.deadline
end
def deadline_formatted= s
self.deadline = s
end
然后,在表格中,
<%= f.label :deadline_formatted, "Deadline" %>
<%= f.text_field :deadline_formatted %>
通过一些我仍然不太理解的轨道魔法*,这足以做到这一点 - 看起来它不应该工作,但它确实有效。 至少它对我有用。
*我不明白的部分是,在表单中设置截止日期字段将继续使用文本字段中的值调用 deadline= 方法。 相反,我调用 deadline_formatted= 方法,它只是将结果传递给 deadline=,所以你会认为结果是相同的。 但是,不知何故,时间从UTC(数据库)到本地时间(表单)来回转换。
您可以尝试使用去本地化 gem: https://github.com/clemens/delocalize