elixir - docs - ecto etimologia
Modificar clave foránea en ecto. (4)
No creo que se pueda lograr con alter table
. Por ejemplo, de acuerdo con esta respuesta, Postgres no permite modificar restricciones en la declaración ALTER TABLE
. MySQL tampoco permite modificar restricciones .
Lo más fácil sería eliminar el campo y volver a agregarlo si no tiene datos. De lo contrario, necesitas usar SQL en bruto con execute
Tengo esta migración original que ya se ha ejecutado y enviado en sentido ascendente:
create table(:videos) do
add :url, :string
add :title, :string
add :description, :text
add :user_id, references(:users, on_delete: :nothing)
timestamps
end
create index(:videos, [:user_id])
Ahora deseo cambiar la clave foránea en user_id
a eliminaciones en cascada, de modo que cuando un usuario sea eliminado, todos sus videos asociados también serán eliminados.
He intentado la siguiente migración:
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
Pero esto plantea un error:
(Postgrex.Error) ERROR (duplicate_object): constraint "videos_user_id_fkey" for relation "videos" already exists
¿Cómo puedo formular un script de migración que cambie esta clave externa de acuerdo con mi requerimiento?
ACTUALIZAR
Terminé con la siguiente solución:
def up do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
end
def down do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :nothing)
end
end
esto elimina la restricción antes de que ecto intente volver a crearla.
No estoy seguro de cuándo se agregó a Ecto, pero al menos en 2.1.6 ya no hay necesidad de SQL en bruto. drop/1
ahora soporta restricciones :
def up do
drop constraint(:videos, "videos_user_id_fkey")
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
end
def down do
drop constraint(:videos, "videos_user_id_fkey")
alter table(:videos) do
modify :user_id, references(:users, on_delete: :nothing)
end
end
Puedes soltar el índice antes de llamar a alter
:
drop_if_exists index(:videos, [:user_id])
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
Hacer lo contrario es un poco más complicado:
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
create_if_not_exists index(:videos, [:user_id])
Terminé con la siguiente solución:
def up do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
end
def down do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :nothing)
end
end
esto elimina la restricción antes de que ecto intente volver a crearla
Copiado de la pregunta.