Skip to content

Migration DSL

Vsevolod Romashov edited this page Mar 13, 2019 · 6 revisions

Migration DSL allows you to describe the operations that modify your database in conditional migrations.

Create table

#create_table expects a name of the created table and a block identical to the one you would pass to a table description in the declarative schema definition.

You can specify fields, indexes, check constraints and foreign keys here.

migrator.create_table :posts do |t|
  t.serial  :id,    primary_key: true
  t.varchar :title, null: false
  t.text    :body
end

Drop table

#drop_table just takes a deleted table's name:

migrator.drop_table :posts

Rename table

#rename_table takes both old and new names of the table:

migrator.rename_table :people, to: :users

Alter table

#alter_table takes a table's name and a block describing the operations (not definitions) that have to be run on that table.

migrator.alter_table :users do |t|
  # operations with the :users table
end

Add column

#add_column takes a column name, it's type and additional options (similar to the options in the column's definition):

migrator.alter_table :people do |t|
  t.add_column :email, :varchar, null: false
end

Drop column

#drop_column just takes the column's name:

migrator.alter_table :people do |t|
  t.drop_column :name
end

Rename column

#rename_column takes old and new names of the column:

migrator.alter_table :people do |t|
  t.rename_column :name, to: :first_name
end

Alter column type

#alter_column_type takes the column's name and it's new type:

migrator.alter_table :people do |t|
  t.alter_column_type :name, :text
end

Changing a column's type from/to one of the PostgreSQL serial types is not supported.

#alter_column_type allows you to specify how to convert the existing data to the new type (it translates to the USING SQL clause):

migrator.alter_table :messages do |t|
  t.alter_column_type :read, :boolean, using: 'read::boolean'
end

This is the only way to change column type with a USING clause; you can't do that with a declarative schema definition.

Allow null

#allow_null removes the NOT NULL constraint from the column; it takes the column's name:

migrator.alter_table :people do |t|
  t.allow_null :name
end

Disallow null

#disallow_null adds the NOT NULL constraint to the column; it also expects just the column's name:

migrator.alter_table :people do |t|
  t.disallow_null :created_at
end

Alter column default

#alter_column_default changes the column's default value; it takes the column's name and a new default (just like in declarative definition, you can pass strings, fixnums, floats, true & false, dates, times and symbols - the latter are interpreted as raw SQL):

migrator.alter_table :people do |t|
  t.alter_column_default :created_at, :'now()'
end

Add primary key

#add_primary_key creates a primary key on the specified columns. It does not create the actual columns, they must already exist in that table.

migrator.alter_table :people do |t|
  t.add_primary_key :id
end

Drop primary key

#drop_primary_key is called without any arguments; it drops the primary key from that table.

migrator.alter_table :people do |t|
  t.drop_primary_key
end

Add index

#add_index expects the same arguments and options as the #index method in the schema definition: you can pass one or several column names (as symbols) and/or expressions (as strings) and optionally specify index name, uniqueness, type, condition (for partial indexes) and columns ordering:

migrator.alter_table :users do |t|
  t.add_index :email, unique: true
end

Drop index

#drop_index expects just the name of the index:

migrator.alter_table :people do |t|
  t.drop_index :people_phone_index
end

Add check

#add_check adds a check constraint; it takes the name of the constraint and a condition as an SQL string:

migrator.alter_table :people do |t|
  t.add_check :name_length, 'character_length(name::text) > 4'
end

Drop check

#drop_check drops a check constraint; it expects just the constraint's name:

migrator.alter_table :people do |t|
  t.drop_check :phone_format
end

Add foreign key

#add_foreign_key creates a foreign key; it expects the same arguments as the #foreign_key method in the schema definition - referencing fields, referenced table, optionally referenced fields, on_update/on_delete actions and the deferrable option:

migrator.alter_table :posts do |t|
  t.add_foreign_key :person_id, references: :people
end

Drop foreign key

#drop_foreign_key just takes the name of the foreign key:

migrator.alter_table :posts do |t|
  t.drop_foreign_key :posts_person_id_fkey
end

Create enum

#create_enum creates an enum datatype; it expects a type's name and an array of possible values:

migrator.create_enum :user_role, [:guest, :user, :admin]

Drop enum

#drop_enum takes just the type's name:

migrator.drop_enum :user_role

Rename enum

#rename_enum takes old and new names of the type:

migrator.rename_enum :user_role, to: :role

Create extension

#create_extension enables a given extension: it takes the name of the extension:

migrator.create_extension :hstore

Drop extension

#drop_extension disables the extension with a given name:

migrator.drop_extension :hstore

Execute

The #execute method allows you to run any SQL statement:

migrator.execute "UPDATE messages SET read = 't'"