我正在将 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.
我猜测这与此有关吗?有没有明显或简单的方法来解决这个问题?我可以使用重新加载语句重构许多测试和生产代码,但这并不理想,我怀疑我错过了一些基本的东西。
解决方案非常简单。在 set_duration 调用上添加
.to_i
解决了这个问题 - 显然将 int 传递给 postgres 而不是 float 会产生很大的差异!
def set_duration
self.duration = (end_datetime - start_datetime).to_i
end