Exists? Don't ignore!

You've been a ruby on rails developer for so long.  You create migrations and never run into trouble.  Suddenly you have multiple changes on your migration and you're now paying attention to indexes more than you used to because your app is now growing and you need to make enhancements.  Sounds like you?

Tip: Don't ignore rails' built in checks for migration.  Clueless?  Read on.


class CreateProducts < ActiveRecord::Migration
  def up
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end

  def down
    drop_table :products
  end
end

Did you forget something? Yes you did!

Indices are important for speeding up your queries. They make a certain "quick bond" with the information that your application almost always retrieves from your data. These may work hand in hand with "Views" but these are the basic necessity if you have very simple requirements.

First off, always check presence of tables before creating them.

table_exists?(table_name)

Next, also check the presence of columns when adding some to an existing table.

column_exists?(table_name, column_name, type = nil, options = {})

Next, also check the presence of indices

index_exists?(table_name, column_name, options = {})

I must elaborate though that there are certain quirks you need to take note of regarding indices. Uniq indices and multiple column indices are very specific.

# Check an index exists
index_exists?(:products, :company_id)

# Check an index on multiple columns exists
index_exists?(:products, [:company_id, :cost])

# Check a unique index exists
index_exists?(:products, [:company_id, :name], :unique => true)

Almost always, you should specify a name for your uniq indices to avoid collision of automatic names and to make use of them for checking existence. In the above example, we should extend to:

# Check a unique index exists
index_exists?(:products, [:company_id, :name], :unique => true, :name =&gt; "products_company_id_and_name_uniq")

If you fail to name your uniq index, it will throw off errors later on. And when you do use uniq indices, make sure that you also do this when you're in the "up" migration (or just creating it for the first time)

# index declarations
Product.destroy_all
# do some data insert/initialization

That's all. I wasted almost an hour trying to fix faulty migrations. So, let that be your saving! :)