Rails 7.2 - 持续时间和 postgres 间隔类型的意外行为

问题描述 投票:0回答:1

我正在将 Rails 应用程序从

7.1.3.4
升级到
7.2
,我对新行为感到非常困惑。

我们有一个类似的对象:

class Event < ApplicationRecord
  before_save :set_duration
  before_save :update_classification

  def set_duration
    self.duration = end_datetime - start_datetime
  end

  def update_classification
    if duration >= 4.hours 
      self.classification = "long"
    else
      self.classification = "short"
    end
  end
end

以及类似的测试:

class EventTest < ActiveSupport::TestCase
  def setup
    @event = build(:event)
  end

  test "duration and classification are updated correctly before_save" do
    @event.start_datetime = Time.now.utc
    @event.end_datetime = 6.hours.from_now.utc

    @event.save!
    assert_equal "Long", @event.classification
    assert_equal 6.hours, @event.duration.round
  end
end

在 Rails

7.1.3.4
中,这一切都过去了。 7.2 升级后,它在最后一行失败:
NoMethodError: undefined method `round' for nil
。使用调试器,我可以看到在
save!
调用之前持续时间和分类都是 nil,但之后只有分类才有值。如果我在
@event.reload
之后调用
save
,则持续时间值会正确加载!在控制台中,保存调用会生成如下 SQL:

Event Create (2.0ms)  INSERT INTO "Events" ("created_at", "updated_at", "start_datetime", "end_datetime", "duration", "classification") VALUES ($1, $2, $3, $4) RETURNING "id"  [["created_at", "2024-10-17 20:51:14.844042"], ["updated_at", "2024-10-17 20:51:14.844042"], ["start_datetime", "2024-10-17 20:50:56.515026"], ["end_datetime", "2024-10-18 02:50:55.377912"], ["classification", "Long"], ["duration", "PT5H59M58.86288599999898S"]]

我们正在使用 Postgres,架构看起来像这样:

  create_table "impairments", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.datetime "start_datetime"
    t.datetime "end_datetime"
    t.string "classification"
    t.interval "duration"
  end

那么,我错过了什么?我注意到在 7.2 发行说明 中,它说:

Remove deprecated support to quote ActiveSupport::Duration.
我猜测这与此有关吗?有没有明显或简单的方法来解决这个问题?我可以使用重新加载语句重构许多测试和生产代码,但这并不理想,我怀疑我错过了一些基本的东西。

ruby-on-rails ruby-on-rails-7.2
1个回答
0
投票

解决方案非常简单。在 set_duration 调用上添加

.to_i
解决了这个问题 - 显然将 int 传递给 postgres 而不是 float 会产生很大的差异!

  def set_duration
    self.duration = (end_datetime - start_datetime).to_i
  end
© www.soinside.com 2019 - 2024. All rights reserved.