Rails 6.1 Adds Check Constraints Support

For adding check constraints until now with Rails, we had to execute raw SQL queries using migrations.

Example

Suppose we want to create a table for Book model with a check constraint on price field that price should be greater than 100. The only way to do this earlier was to write a migration with a raw sql query after creating table as given below:

class CreateBooks < ActiveRecord::Migration
  def change
    create_table :books do |t|
      t.string :name
      t.integer :price
    end
  end
end
class AddConstraintToBooks < ActiveRecord::Migration
  def up
    execute "ALTER TABLE books ADD CONSTRAINT price_check CHECK (price > 100)"
  end

  def down
    execute "ALTER TABLE books DROP CONSTRAINT price_check"
  end
end

Moreover, this was an irreversible migration hence had to add it separately with up and down methods.

Solution? check_constraint, :add_check_constraint and remove_check_constraint

Rails 6.1 now allows adding check_constraint to rails migration when creating table as well as DSL to create check_constraints via migration after the table has been created.

Syntax for adding check_constraint at the time of table creation is:

create_table :table_name do |t|
  ...
  t.check_constraint [constraint_name], [constraint]
end

Syntax for adding and removing check_constraint to an already existing table is:

add_check_constraint :table_name, :constraint_condition, name: "constraint_name"
remove_check_constraint :table_name, name: "constraint_name"

Notice that both add_check_constraint and remove_check_constraint are reversible.

Example:

In the previous Book example.

Notice that we are adding check_constraint when creating the books table itself:

class CreateBooks < ActiveRecord::Migration
  def change
    create_table :books do |t|
      t.string :name
      t.integer :price
      t.check_constraint "price_check", "price > 100"
    end
  end
end

For adding a price_check constraint to books table through a separate migration:

class CreateBooks < ActiveRecord::Migration
  def change
    add_check_constraint :books, "price > 100", name: "price_check"
  end
end

And for removing the price_check constraint from books table through a separate migration:

class CreateBooks < ActiveRecord::Migration
  def change
    remove_check_constraint :books, name: "price_check"
  end
end

Need expert help with Rails database work?

Saeloun is a Rails Foundation Contributing Member helping teams modernize, upgrade, scale, and maintain production Rails applications.

Our Expertise

  • Rails contributors
  • 500+ Technical Articles
  • Production Rails consulting
  • Performance Optimization

Services

  • Rails application development
  • Code Audits
  • Rails upgrades
  • Team Augmentation

Need help on your Ruby on Rails or React project?

Join Our Newsletter