升级到Rails 5.2:如何避免非可选关联的“可选:true”?

时间:2019-04-30 05:35:26

标签: ruby-on-rails ruby-on-rails-5

将我的应用程序从Rails 4.2.8移动到5.2.3后,插入失败并

Billings event must exist

应用程序接收到一个具有一个事件和许多相关账单的级联哈希,应将其以 one single transaction 的形式放入数据库中;以前确实如此。

class Event < ActiveRecord::Base
  has_many :billings, -> { where('1 = 1') }, dependent: :destroy
  accepts_nested_attributes_for :billings
  validates_associated :billings
end

class Billing < ActiveRecord::Base
  belongs_to :event  
  validates_presence_of :event_id, on: :update
end

class EventsController < ApplicationController
  def kC
    @event = Event.new(event_params)
    if @event.save
       [doesn't get here anymore]
    end
  end
end

没有计费控制器,它们仅通过关联的事件存在。

快速分析发现文档中提到

belongs_to :event, optional: true

将避免此错误,的确如此。但这对我来说似乎很不对劲,因为在此应用程序中,账单必须从不不存在,它是 NOT 可选! 但是,正确的解决方案是什么?

进一步的分析表明:所有验证都得到处理,但是从未达到过before_create()回调。 “必须存在”错误是在内部某个地方添加的,它不是来自我的代码。

此外,当仅使用上述代码创建模板时,我发现问题代码为范围-> { where('1 = 1') }

在实际应用中,这是一个更复杂(也更有用)的术语,但这个简单且看似透明的术语会同样触发问题。

这里有很多类似的问题,但是很多情况下,这种关联确实是可选的,有些具有非标准的命名(我不认为我有像以前那样的名称),但是我没有找到一个在这种情况下,所属模型通过拥有模型得到了完全处理。

2 个答案:

答案 0 :(得分:1)

在Rails 5中,每当我们定义一个belongs_to关联时,默认情况下都需要显示关联的记录。如果相关记录不存在,则会触发验证错误。要删除此默认行为,我们可以使用Rails 5随附的 new_framework_defaults.rb 初始化程序。

(有关更多信息,您可以检查此https://github.com/rails/rails/pull/18937

从较旧版本的Rails升级到Rails 5时,我们可以通过运行bin/rails app:update任务来添加此初始化程序。

此新添加的初始化程序具有以下配置标志,用于处理默认行为

Rails.application.config.active_record.belongs_to_required_by_default = true

我们可以通过将其值设置为 false

来关闭此行为
Rails.application.config.active_record.belongs_to_required_by_default = false

答案 1 :(得分:0)

我找到了正确的解决方案:

class Event < ActiveRecord::Base
  has_many :billings, -> { where('1 = 1') }, dependent: :destroy, inverse_of: :event
  accepts_nested_attributes_for :billings
  validates_associated :billings
end

以这种方式添加此inverse_of:选项可以解决该问题。

初步的根本原因分析:

inverse_of选项的(稀疏)文档的确建议将其添加到belongs_to功能中;它并没有提及将其添加到has_many中(这也不妨碍)。在这种情况下,将其添加到belongs_to不会有所改善,文档中的用例也不适用于此。

尽管如此,文档中提到了关联的“自动猜测”,并且在AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS中声明的某些情况下,这种自动猜测将被省略。 在源中搜索该术语会导致使用私有方法can_find_inverse_of_automatically?(),很明显,作用域也会导致自动猜测被忽略。

看来,以某种方式对累积插入进行解散需要查明“ inverse_of”(是自动还是已编码),否则,由于提到的更改,它会认为拥有关系不存在-与后者的所有权关系不存在在Rails 5中,现在会导致验证错误。