首页 > 解决方案 > 升级到 Rails 5.2:如何避免非可选关联的“可选:真”?

问题描述

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

Billings event must exist

应用程序接收一个带有一个事件和许多相关帐单的单个级联散列,并应在一个 事务中将其放入数据库;这以前总是有效的。

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

会避免这个错误,确实如此。但这对我来说似乎很错误,因为在这个应用程序中,如果没有他们的事件,账单就永远不会存在,这不是可选的!但是,正确的解决方案是什么?

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

此外,当只使用上面显示的代码创建模板时,我发现有问题的代码是作用域-> { where('1 = 1') }

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

这里有很多类似的问题,但是,很多情况下关联确实是可选的,有些有非标准命名(我不认为我有,因为它以前工作过),我没有找到适合这种情况的归属模型是通过拥有一个完全处理的。

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

解决方案


在 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

推荐阅读