Предположим, у меня есть две модели: Родитель и ребенок. Если обновлена дочерняя запись, есть ли возможность автоматически обновить временную метку родительской записи?Автоматическое обновление поля родительской записи update_at (Elixir-Ecto)
ответ
Есть несколько способов сделать это. Один из них требует мастера эктопаразитов (скоро будут Ecto v2.0) и простое обновление родителя непосредственно:
# Assuming a child_changeset with the parent loaded
child_changset = Ecto.Changeset.put_assoc(child_changeset, :parent, %{updated_at: Ecto.DateTime.utc})
Теперь, когда ребенок сохраняется, она будет автоматически распространяться изменениями родителя.
В качестве альтернативы, вы можете использовать экто v1.1 с prepare_changes и update_all для распространения изменений:
# Assuming a child_changeset
Ecto.Changeset.prepare_changes child_changeset, fn changeset ->
query = Ecto.assoc(changeset.model, :parent)
changeset.repo.update_all query, set: [updated_at: ^Ecto.DateTime.utc]
changeset
end
В этом примере мы используем prepare_changes, который выполняется в транзакции вместе с детьми, чтобы изменения строить запрос, представляющий родительскую модель, и выпуск update_all, обновляющий все столбцы updated_at для модулей, соответствующих запросу.
Вы можете добавить функцию в набор изменений, который проверяет наличие изменений и если они действительны (это если вы обновляете ассоциации через родительский набор изменений).
def touch_parent(%{changes: changes, valid: true}=changeset) when map_size(changes) > 0 do
updated_at = DateTime.utc_now() |> DateTime.to_naive()
cast(changeset, %{updated_at: updated_at}, [:updated_at])
end
def touch_parent(changeset), do: changeset
Вы можете положить, что в конце вашей update_changeset
функции для модели.
def update_changeset(%Model{}=model, attrs) do
model
# casting
|> touch_parent()
end
Если вы хотите просто сделать определенные ассоциации вы могли бы сделать что-то вроде этого:
def touch_parent(%{changes: changes, valid: true) when map_size(changes) > 0 do
updated_at = DateTime.utc_now() |> DateTime.to_naive()
changed_fields = Map.keys(changes)
cond do
:association in changed_fields ->
cast(changeset, %{updated_at: updated_at}, [:updated_at])
true -> changeset
end
end
:)