【问题标题】:Rails - Strange time_select buggy behaviorRails - 奇怪的 time_select 错误行为
【发布时间】:2020-09-02 07:01:39
【问题描述】:

我的 rails repo 示例在这里: https://github.com/johndel/strange_timeselect

奇怪行为的复制可以在这里显示: https://captain24.herokuapp.com/availabilities/new

time_select 有以下问题: 在一个带有 postgresql 的新 Rails 应用程序中,我有一个模型 (availabilities),它的 started_at 列在 postgres 中的类型为 time。当我创建新记录时,它会保存started_at 值,比所选值早一小时。在更新时它可以正常工作。

我注意到以下内容: 我只能在he​​roku上复制它(在本地我无法复制它)。它仅在创建时有效,并且仅在我在 application.rb 上设置 default_timezone 后才有效,正如您在 commit 上看到的那样。

该应用程序还有另一个名为 tasks 的模型,其列名为 started_at 并键入 datetime。这个工作总是正确的,但它节省了与availabilitiestime 字段不同的时区的时间。

如果我在 time_select 字段上添加ignore_date: true 可以修复它,但我想知道为什么会发生这种情况?这是正常的,我错过了什么吗?或者是一些非常奇怪的 ruby​​ 或 rails 错误?还是 Heroku 上的 postgresql 存在问题/配置错误?

更新: 因为 @max 要求我进一步解释代码,所以这里是:

关于代码,现在它只是两个脚手架资源,命令为rails g scaffold tasks started_at:datetimerails g scaffold availabilities started_at:time。所以一个是tasks,另一个是availabilities,每个模型只有一列。我还在config/application.rb 中添加了这几行代码:

config.time_zone = 'Athens'
config.active_record.default_timezone = :local

可用性表单的代码是这样的(简单的脚手架):

<%= form_with(model: task, local: true) do |form| %>
  <% if task.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(task.errors.count, "error") %> prohibited this task from being saved:</h2>

      <ul>
        <% task.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :started_at %>
    <%= form.time_select :started_at %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

可用性迁移代码如下:

class CreateAvailabilities < ActiveRecord::Migration[6.0]
  def change
    create_table :availabilities do |t|
      t.time :started_at

      t.timestamps
    end
  end
end

如果你添加上面的代码并部署在heroku上,你将能够重现问题。

所以关于上面代码的问题是,当我创建一个availability 记录时,它比选择的记录少一小时。这仅在创建时发生。 task 记录不是这种情况,因此它可能与 time postgres 类型和 active_record 时区有关。这仅在 heroku 上发生,您可以查看上面的链接。

【问题讨论】:

  • 很难从描述代码功能的文本中做出任何有意义的事情。它真的只会产生更多的问题。而是尝试创建一个最小的可验证示例来重现您正在谈论的行为。不 - 添加到您的 github 存储库的链接不是一回事。
  • 我认为我的要求很简单。我拥有无需任何努力即可重现错误的实时代码以及存储库上的代码(它只有 3 次提交,因此很容易理解发生了什么变化)。所以我在问,上述行为是否正确且符合预期,我做错了什么(以及那是什么)还是我们应该在 Rails 存储库上放一张票,因为它是一个错误?
  • 您可能会这么认为,但您并没有真正帮助我们排除任何问题,而是要求读者深入研究您的代码以找出问题所在。
  • 好的,我会添加更多解释。
  • 为什么不使用 UTC?您想通过非标准服务器时间来解决什么问题?

标签: ruby-on-rails ruby postgresql heroku activerecord


【解决方案1】:

有两个不同的问题。

1) 本地与 Heroku 的不同场景。 - 您的 schema.rb 文件已将“started_at”列为日期时间,而在迁移中,它是“时间” - Heroku 运行迁移,但 bin/rails db:setup 从 schema.rb 加载,因此您在本地看不到问题,因为它保存为日期时间。

2) 时间列的问题在于缺少日期,Ruby 不得不猜测。当您创建新记录时,表格会预先填写当前日期,在发布时,该日期是 5 月(夏季月份),并将在 EEST 中进行解析。 传入的属性"2020", "05", "20", "11", "00" 将被解析为Wed, 20 May 2020 11:00:00 EEST +03:00

然后将其保存在数据库中作为时间偏移 -3 小时 8:00:00

当它下次从数据库中加载时,没有附加日期,因此 Rails 使用 "2000", "01", "01" 的日期假设对其进行解析,从而得到 Sat, 01 Jan 2000 10:00:00 EET +02:00。请注意,在这种情况下只添加了两个小时,因为它是 EET。

当您编辑时,表单会预先填写可用性的当前started_at Sat, 01 Jan 2000 10:00:00 EET +02:00。当您更新时,由于表格中的日期现在是一月,因此使用 EET 时区对其进行解析并立即保存。由于用于显示和编辑的日期相同,现在看起来“正确”

如何解决?这取决于应用程序,我不是专家,但有一些想法:-

1) 有人会说,没有日期,时间本来就没有意义。也许您可以考虑改用 datetime 列。希腊的 12PM 可用性对于不同时区的人来说可能意味着不同。

2) 您可以使用 tod gem 之类的东西来处理时间。

3) 您可以将其存储为从上午 12 点开始的整数偏移量。

【讨论】:

    【解决方案2】:

    发生这种情况是因为您需要考虑服务器的时区。 您还需要配置 Heroku。更改 Heroku 时间设置的命令如下所示

    heroku config:add TZ="Europe/Paris"

    将日期保存为 UTC 以外的任何其他格式都不是一个好主意

    Details

    编辑

    要回答为什么更新方法工作方式不同的问题,您必须检查 rails 呈现的表单。Rails 创建了额外的三个隐藏字段

    availability[started_at(1i)],

    availability[started_at(2i)]

    availability[started_at(3i)]

    在创建表单上,这些字段的默认值为 2020,5,19

    但在编辑表单上,它们的值为 2000,1,1

    我有根据的猜测是他们搞砸了夏令时,从而造成了异常。

    【讨论】:

    • 我同意在非 UTC 上不节省时间的部分。但是为什么会在创建而不是更新时发生这种情况?
    • 更新了答案。请检查:)
    猜你喜欢
    • 1970-01-01
    • 2012-11-26
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多