Add & Remove Model NOT NULL Constraint - Rails Migration
My style of coding keeps models slim preferably with no business logic (including validation) and database tables without constraints the likes of NOT NULL
, CHECK
and EXCLUDE
where data integrity is not of a a concern. These are things I usually delegate to relevant form objects. Call it a bad habit, but especially with relations I would like to keep the possibility to nullifying it when needed.
On Create Table
You might be wanting to make table (new model) with a field not nullable with the null: false
option to make a field not nullable or null: true
to make make nullable.
class CreateOrders < ActiveRecord::Migration[6.1]
def change
create_table :orders do |t|
# ...
t.references :cart, null: false, foreign_key: true
t.references :user, null: true, foreign_key: true
# ...
end
end
end
This will create a cart_id
and user_id
field in the orders
table that are not only foreign keys (when not null needs to adhere to referential integrity) but also nut nullable.
On Existing Table
If you have an existing table, you will need to use the add_column
for a new column that is constrained by the null: false
option. If you wan to update an existing column you will have to use the change_column_null
method.
# New column
add_column :orders, :cart_id, :bigint, null: false
add_column :orders, :user_id, :bigint, null: true
# Change column
change_column_null :orders, :cart_id, false
change_column_null :orders, :user_id, true
Default Values
Before you are making a column NOT NULL
you would want to make user there are no cells that are null or you risk running in to an exception. You can do this by providing a default value or manually setting the value using a loop.
class MakeOrderReferenceNotNull < ActiveRecord::Migration[6.1]
def up
Order.where(reference: nil).each do |order|
order.update(reference: OrderReferenceGenerator.for(order))
end
change_column_null :orders, :reference, false
end
end
or you can add a default value to the change_column_null
method.
class MakeOrderReferenceNotNull < ActiveRecord::Migration[6.1]
def up
change_column_null :orders, :reference, false, Time.zone.now.to_i
end
end
Rails 3
The change_column_null
has been with ActiveRecord since Ruby on Rails 4. In case you are rocking an old Ruby on Rails project (which you shouldn't) you will have to use the change_column
as...
class MakeOrderReferenceNotNull < ActiveRecord::Migration
def change
Order.where(reference: nil).each do |order|
order.update(reference: OrderReferenceGenerator.for(order))
end
change_column :orders, :reference, :string, null: false
end
end
About the Author
Ziyan Junaideen -
Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.