обновить до Rails 5.2: как избежать «необязательного: истинного» для не необязательных ассоциаций? - PullRequest
0 голосов
/ 30 апреля 2019

После перемещения моего приложения из Rails 4.2.8 в 5.2.3 вставки завершаются с ошибкой

Billings event must exist

Приложение получает один каскадный хэш с одним событием и множеством связанных счетов и должен поместить его в базу данных в виде one single транзакция ; это всегда работало раньше.

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') }

В реальном приложении это более сложный (и более полезный) термин, но этот простой и, казалось бы, прозрачный термин вызывает проблему точно так же.

Здесь много подобных вопросов, но тогда у многих возникает ситуация, когда ассоциация действительно необязательна, у некоторых есть нестандартные наименования (я не думаю, что у меня, как это было раньше), и я не нашел ни одного для этого случая, когда принадлежащая модель полностью обрабатывается через имеющую.

Ответы [ 2 ]

1 голос
/ 01 мая 2019

Я нашел правильное решение:

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?(), где становится очевидным, что также scope приведет к тому, что автоматическое угадывание будет опущено.

Похоже, что распутываниекумулятивной вставки каким-то образом нужно точно определить «inverse_of» (будь то автоматически или закодировано), или в противном случае он будет считать отношение-владелец несуществующим - с последним, из-за упомянутого изменения в Rails 5, которое сейчас приводит кошибка проверки.

0 голосов
/ 30 апреля 2019

В Rails 5 всякий раз, когда мы определяем ассоциацию belongs_to, требуется, чтобы соответствующая запись присутствовала по умолчанию. Это вызывает ошибку проверки, если соответствующая запись отсутствует. Чтобы удалить это поведение по умолчанию, мы можем использовать new_framework_defaults.rb инициализатор, который поставляется с Rails 5.

(Для получения дополнительной информации вы можете проверить это 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...