Как я могу сохранить идентификатор дочерней записи в родительском файле без повторного вызова .save? - PullRequest
0 голосов
/ 30 мая 2019

У меня проблема, когда устаревший код вызывал .save внутри after_save обратного вызова до Rails 5.1, но из-за того, как saved_change_to_attribute заменяет attribute_changed? в after_ обратных вызовах, это проблема для вызова .save дважды (.save влияет на .changes).

Теперь мне нужно повторить то же поведение, не вызывая .save дважды.

В моем приложении Rails 5.1.7 (подготовка к обновлению 5.2):

class OtherModel < ApplicationRecord
  belongs_to :my_model, inverse_of: :other_model_history
end

class MyModel < ApplicationRecord
  has_many :other_model_history, class_name: 'OtherModel', inverse_of: :my_model
  belongs_to :latest_other_model, class_name: 'OtherModel'
  before_create :initialize_first_other_model

  def initialize_first_other_model
    initial_other = OtherModel.new(name: 'initial')
    other_model_history << initial_other
    latest_other_model = initial_other
    # When it finally reaches save (this is before_create) I want ActiveRecord to know
    # to save the ID of initial_other in latest_other_model_id ... but it doesn't
  end
end

Когда вызывается MyModel.new.save, initialize_other_model создает начальный экземпляр OtherModel с правильным other_model.my_model_id на основе my_model.id.

НО, my_model.latest_other_model_id - ноль.Это несмотря на то, что latest_other_model правильно ссылается на объект initial_other.

Как я могу сказать ActiveRecord, что он должен установить my_model.latest_other_model_id = initial_other.id?

РЕДАКТИРОВАТЬ: с ActiveRecord::Base.logger = Logger.new(STDOUT)

DEBUG -- :   SQL (0.3ms)  INSERT INTO "my_models" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2019-05-31 06:12:27.006455"], ["updated_at", "2019-05-31 06:12:27.006455"]]
DEBUG -- :   SQL (0.1ms)  INSERT INTO "other_models" ("my_model_id", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["my_model_id", 3], ["name", "initial"], ["created_at", "2019-05-31 06:12:27.015472"], ["updated_at", "2019-05-31 06:12:27.015472"]]
DEBUG -- :    (1.5ms)  commit transaction

Вы видите, что MyModel вставляется первым, безother_model, затем OtherModel вставляется с идентификатором из MyModel.Я хочу, чтобы Rails также знал, чтобы затем вставить my_models.latest_other_model_id, не вызывая .save

1 Ответ

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

Я смог использовать update_column в after_save. Это сохраняет ссылку от my_model до other_model без влияния на saved_changes. Мои обратные вызовы теперь

before_create:

  initial_other = OtherModel.new(name: 'initial')
  other_model_history << initial_other

after_save:

update_column('latest_other_model_id', other_model_history.last.id)

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

...