Model Generators

The model and scaffold generators will generate migrations suitable for creating a new model. The migration will contain instructions for creating the appropriate table. If you tell Rails which columns you want, expressions to add those columns will also be generated. For example, running:

$ bin/rails generate model Product name:string description:text

will create a migration that looks like this

class CreateProducts < ActiveRecord::Migration[5.0]

  def change

    create_table :products do |t|

      t.string :name

      t.text :description

      t.timestamps

    end

  end

end

You can define as many column_name/type pairs as you like.

Passing modifiers

Some commonly used type modifiers can be passed directly on the command line. They are specified in curly braces and follow the field type:

For example, running:

$ bin/rails generate migration AddDetailsToProducts ‘price:decimal{5,2}’ supplier:references{polymorphic}

will create a migration that looks like this:

class AddDetailsToProducts < ActiveRecord::Migration[5.0]

  def change

    add_column :products, :price, :decimal, precision: 5, scale: 2

    add_reference :products, :supplier, polymorphic: true

  end

end

TIP: For details, look at the generated messages from the generator.

(writing-a-migration) Writing a migration

Once you’ve created your migration using one of the generators, it’s time to get to work!

Create a table

The create_table method is one of the most fundamental, but in most cases, it will be generated for you by the model or scaffold generator. The usual use is

create_table :products do |t|

  t.string :name

end

This will create a products table with a name column (and, as discussed above, an implied id column).

By default, create_table will create a primary key named id. You can change the name of the primary key with the :primary_key option (don’t forget to update the corresponding model as well), or if you don’t want a primary key at all, you can specify the id: false option. If you need to pass specific options to the database, you can put the SQL snippet in the :options option. For example:

create_table :products, options: “ENGINE=BLACKHOLE” do |t|

  t.string :name, null: false

end

will add ENGINE=BLACKHOLE to the SQL statement used to create the table (when using MySQL or MariaDB, ENGINE=InnoDB is passed by default).

It is also possible to pass the :comment option with any description for the table, which will be stored in the database itself and can be viewed using database administration tools such as MySQL Workbench or PgAdmin III. It is highly recommended to leave comments in migrations for applications with large databases, as it helps to understand the data model and generate documentation. Currently only MySQL and PostgreSQL adapters support comments.

Create a join table

The create_join_table migration method creates a HABTM (has and belongs to many) join table. The usual usage would be like this:

create_join_table :products, :categories

which will create a categories_products table with two columns named category_id and product_id. These columns have the :null option set to false by default. This can be overridden with the :column_options option:

create_join_table :products, :categories, column_options: { null: true }

By default, the name of the join table is obtained as the concatenation of the first two arguments passed to create_join_table, in alphabetical order. To customize the table name, pass the :table_name option:

create_join_table :products, :categories, table_name: :categorization

creates a categorization table.

By default, create_join_table will create two columns with no options, but you can specify these options using the :column_options option. For example,

create_join_table :products, :categories, column_options: {null: true}

will create a product_id and a category_id with the :null option set to true.

create_join_table also accepts a block that can be used to add indexes (which are not created by default) or additional columns:

create_join_table :products, :categories do |t|

  t.index :product_id

  t.index :category_id

end

Changing tables

A close relative of create_table is change_table, used to change existing tables. It is used like create_table, but the object passed to the block has more methods. For example:

change_table :products do |t|

  t.remove :description, :name

  t.string :part_number

  t.index :part_number

  t.rename :upccode, :upc_code

end

removes the description and name columns, creates a part_number string column, and adds an index on it. Finally, it renames the upccode column.

Changing columns

Like remove_column and add_column, Rails provides a migration change_column method.

change_column :products, :part_number, :text

It changes the type of the part_number column in the products table to :text. Note that the change_column command is irreversible.

In addition to change_column, the change_column_null and change_column_default methods are used to change the non-null constraint or default value of a column.

change_column_null :products, :name, false

change_column_default :products, :approved, from: true, to: false

This will set the :name field in products to be a NOT NULL column and change the default value for the :approved field from true to false.

Note: It is also possible to write the previous change_column_default migration as change_column_default :products, :approved, false, but unlike the previous example, this would make your migration irreversible.

(Column Modifiers) Column Modifiers

Column modifiers can be applied when creating or modifying a column:

limit Sets the maximum size of string/text/binary/integer fields.

precision Specifies the precision for decimal fields, which specifies the total number of digits in the number.

scale Specifies the scale for decimal fields, which specifies the number of digits after the decimal point.

polymorphic Adds a type column for belongs_to relationships.

null Allows or disallows NULL values ​​in the column.

default Allows you to set a default value for a column. Note that if you use a dynamic value (such as a date), the default value will only be calculated once (ie, on the date the migration is applied).

index Adds an index for a column.

comment Adds a comment for a column.

Some adapters may support additional options; see the API documentation for specific adapters for details.

NOTE: You cannot specify null and default on the command line.

(foreign-keys) Foreign keys

Although not required, you may want to add foreign key constraints to enforce referential integrity.

add_foreign_key :articles, :authors

This will add a new foreign key to the author_id column of the articles table. The key refers to the id column of the authors table. If column names cannot be derived from table names, the :column and :primary_key options can be used.

Rails will generate a name for each foreign key starting with fk_rails_ plus 10 characters that are deterministically generated based on from_table and column. There is also a :name option if you want to specify a different name.

NOTE: Active Record only supports foreign keys for individual columns. To use composite foreign keys, execute and structure.sql are required. See Export Schema

Removing a foreign key is also easy:

# let Active Record figure out the column name

remove_foreign_key :accounts, :branches

# remove the foreign key for a specific column

remove_foreign_key :accounts, column: :owner_id

# remove the foreign key by name

remove_foreign_key :accounts, name: :special_fk_name

When Helpers Are Not Enough

If the helpers provided by Active Record are not enough, you can use the execute method to run arbitrary SQL:

Product.connection.execute(“UPDATE products SET price = ‘free’ WHERE 1=1”)

See the API documentation for more details and examples of individual methods. In particular, the documentation for ActiveRecord::ConnectionAdapters::SchemaStatements (which provides methods available in the up, down, and change methods), ActiveRecord::ConnectionAdapters::TableDefinition (which provides methods available on the object passed in the create_table method), and ActiveRecord: :ConnectionAdapters::Table (which provides the methods available on the object passed in the change_table method).

Using the change method

The change method is the main method for writing migrations. It works in most cases where Active Record knows how to reverse the migration automatically. Currently, the change method only supports these migration definitions:

add_column

add_foreign_key

add_index

add_reference

add_timestamps

change_column_default (requires :from and :to options)

change_column_null

create_join_table

create_table

disable_extension

drop_join_table

drop_table (you need to specify a block)

enable_extension

remove_column (requires type)

remove_foreign_key (you need to specify the second table)

remove_index

remove_reference

remove_timestamps

rename_column

rename_index

rename_table

change_table is also reversible until the block calls change, change_default, or remove.

remove_column is reversible by providing the column type as the third argument. Also provide options for the original column, otherwise Rails won’t be able to exactly recreate that column on rollback:

remove_column :posts, :slug, :string, null: false, default: ”, index: true

If you need to use other methods, you should use reversible or write the up and down methods instead of the change method.

Leave a Reply

Your email address will not be published.