#ruby-on-rails #activemodel
#ruby-on-rails #activemodel
Вопрос:
У меня есть следующее:
class ModelA < ApplicationRecord
has_many :model_bs, dependent: :destroy
end
class ModelB < ApplicationRecord
belongs_to :model_a
after_destroy :action_only_if_model_a_exists
private
def action_only_if_model_a_exists
# Do things
end
end
Когда я вызываю model_a.destroy
, мне нужно иметь возможность определить в action_only_if_model_a_exists
обратном вызове в ModelB, существует ли еще связанная модель или она также вот-вот будет уничтожена.
Есть ли хороший встроенный в Rails способ сделать это или мне нужно пойти по пути установки флага в ModelA в более раннем обратном вызове (например, before_destroy
), который я могу затем проверить в обратном вызове ModelB?
Редактировать
Я провел несколько тестов и подтвердил, что внутри action_only_if_model_a_exists
обратного вызова выполнение следующего не помогает:
> model_a.persisted?
true
> model_a.destroyed?
false
> model_a.frozen?
false
Комментарии:
1. Вы ожидаете обнулить идентификаторы модели b в качестве стратегии или фактически удалить записи? Кроме того, вас беспокоит задержка в несколько миллисекунд или на самом деле есть какой-то случай, когда вы на самом деле не ожидаете, что modela будет уничтожена, даже если был вызван modela.destroy?
2. Я ожидаю удалить записи.
3. И содержимое
action_only_if_model_a_exists
метода запускает асинхронный процесс, для завершения которого требуется несколько минут, и произойдет сбой, если соответствующая модель больше не существует.4. Я в замешательстве. Если вы вызываете modela.destroy, то обязательно к моменту уничтожения modelb modela должна быть уничтожена, а также сразу после завершения процесса db, поскольку вы вызвали метод для этого, чтобы сделать именно это. Кажется, лучшим способом было бы вызвать modela.modelb.destroy_all с вашего контроллера, затем, когда вы подтвердите, что процесс modelb завершен, явно уничтожьте modela во втором вызове.
5. Порядок действий, по-видимому, следующий:
model_a before_destroy callback
—model_b before_destroy callback
—model_b after_destroy callback
—model_a after_destroy_callback
Это означает, что когда model_b уничтожается, model_a все еще существует в базе данных.
Ответ №1:
Вы можете использовать destroyed_by_association
атрибут в дочернем элементе, чтобы увидеть, уничтожается ли объект как часть dependent: :destroy
от его родительского элемента.
Ответ №2:
Я не смог найти хороший способ сделать это, поэтому я остановился на следующем:
class ModelA < ApplicationRecord
attr_accessor :destroying?
has_many :model_bs, dependent: :destroy
def destroy
self.destroying? = true
super
end
end
class ModelB < ApplicationRecord
belongs_to :model_a
after_destroy :action_only_if_model_a_exists
private
def action_only_if_model_a_exists
if !model_a.destroying?
# Do things
end
end
end
Ответ №3:
Вероятно, самый простой способ достичь этого — использовать before_destroy
обратный вызов в ModelA
для вызова требуемой функции для всех связанных с ней ModelB
функций
class ModelA < ApplicationRecord
has_many :model_bs, dependent: :destroy
before_destroy { |model_a| model_a.model_bs.each { |model_b| model_b. action_only_if_model_a_exists } }
end
Конечно, action_only_if_model_a_exists
не должен быть приватным.
Кроме того, вы захотите учесть, сколько model_bs
у любого данного model_a
объекта, вероятно, будет, и при необходимости рассмотрите возможность использования in_batches
вместо each
.
Обновить
Хорошо, основываясь на вашем обновленном объяснении, и мое понимание теперь противоположно тому, что было ранее, как насчет следующего?
class ModelB < ApplicationRecord
belongs_to :model_a
after_destroy :action_if_not_called_from_model_a
private
def action_if_not_called_from_model_a
if !caller.join.match(/model_a/)
# Do things
end
end
end
Комментарии:
1. Я думаю, что мой вопрос, должно быть, был неясен — это противоположно поведению, которого я на самом деле добиваюсь: я хочу только
action_only_if_model_a_exists
запускать, еслиmodel_b.destroy
вызывается, а не еслиmodel_a.destroy
вызывается.