Rails уничтожает существующего потомка has_one до появления ошибки валидации - PullRequest
1 голос
/ 03 апреля 2020

У меня есть модельное отношение, подобное этому:

class Parent < ApplicationRecord
  has_one :child, dependent: destroy
end

class Child < ApplicationRecord
  belongs_to :parent
end

Внешний ключ находится в таблице childs:

t.belongs_to :parent, index: { unique: true }, foreign_key: true

В childs_controller у меня есть create метод по маршруту POST /parents/<id>/childs:

def create
  @parent = Parent.find(params[:id])

  @child = @parent.create_child! params[:child]

  render json: @child, status: 200
end

Когда я впервые отправляю данные POST на этот контроллер, дочерняя модель создается соответственно. Когда я снова отправляю дочерние данные в контроллер , он выдает ошибку проверки, так как родительский идентификатор уже занят. Это ожидается. Однако существующий ребенок уничтожается одновременно. Это означает, что когда я отправляю данные в третий раз, создается новый дочерний элемент.

Соответствующий журнал, в котором удален дочерний элемент, выглядит следующим образом:

Child Exists? (0.3ms)  SELECT 1 AS one FROM "childs" WHERE "childs"."parent_id" = $1 LIMIT $2  [["parent_id", 1], ["LIMIT", 1]]
 (0.2ms)  ROLLBACK TO SAVEPOINT active_record_3
Child Load (0.3ms)  SELECT "childs".* FROM "childs" WHERE "childs"."parent_id" = $1 LIMIT $2  [["parent_id", 1], ["LIMIT", 1]]
 (0.2ms)  SAVEPOINT active_record_3
Child Destroy (0.2ms)  DELETE FROM "childs" WHERE "childs"."id" = $1  [["id", 1]]
 (0.2ms)  RELEASE SAVEPOINT active_record_3

ERROR: Validation failed: Parent has already been taken

Я могу обойти это оборачивая создание в транзакцию:

Parent.transaction do
  @child = @parent.create_child! params[:child]
end

Но я не понимаю, почему это неожиданно работает.

Итак:

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