I recently wanted to rename a model and its postgres table in a Phoenix app. Renaming the table was simple and documented, but the table also had constraints, sequences, and indexes that needed to be updated in order for the Ecto model to be able to rely on default naming conventions. I couldn't find any examples of what this would look like but was eventually able to figure it out. For anyone else in the same situation, hopefully this example helps.
In the example below, I'm renaming the Permission
model to Membership
. This model belongs to a User
and an Account
, so it has foreign key constraints that need to be renamed.
defmodule MyApp.Repo.Migrations.RenamePermissionsToMemberships do
use Ecto.Migration
def up do
# Drop the existing forgeign key and primary key constraints by their
# default names from when they were generated automatically by Ecto.
drop constraint(:permissions, "permissions_user_id_fkey")
drop constraint(:permissions, "permissions_account_id_fkey")
drop constraint(:permissions, "permissions_pkey")
# Rename the table
rename table(:permissions), to: table(:memberships)
alter table(:memberships) do
# "Modifying" the columns rengenerates the constraints with the correct
# new names. These were the same types and options the columns were
# originally created with in previous migrations.
modify :id, :bigint, primary_key: true
modify :user_id, references(:users)
modify :account_id, references(:accounts)
end
# Rename the ID sequence. I don't think this affects Ecto, but it keeps
# the naming and structure of the table more consistent.
execute "ALTER SEQUENCE permissions_id_seq RENAME TO memberships_id_seq;"
end
# This is just the inverse, restoring the table and its constraints,
# indexes, and sequences to their original names.
def down do
drop constraint(:memberships, "memberships_user_id_fkey")
drop constraint(:memberships, "memberships_account_id_fkey")
drop constraint(:memberships, "memberships_pkey")
rename table(:memberships), to: table(:permissions)
alter table(:permissions) do
modify :id, :bigint, primary_key: true
modify :user_id, references(:users)
modify :account_id, references(:accounts)
end
execute "ALTER SEQUENCE memberships_id_seq RENAME TO permissions_id_seq;"
end
end
This was super helpful! Thanks!
You could also use
ALTER INDEX RENAME
andALTER TABLE RENAME CONSTRAINT
which might be a little safer if you're running against a database that's in use, as the constraints never get dropped.