Database
Last updated
Was this helpful?
Last updated
Was this helpful?
By default, Rails will dump the database structure in a file called schema.rb
every time you run your migrations. This schema.rb
is like one huge migration that is executed when restoring your database so that you don't have to run through every migration you ever ran, and it's the single source of truth for your database schema. schema.rb
is a Ruby file so it's portable between databases - regardless of whether you are running MySQL or Postgres or sqlite3, you will get a similar result.
However, using schema.rb
prevents you from using cool features that your database of choice () has. (One such example is native support for enums). If you create a migration that uses a database-specific structure and try to dump it to schema.rb
, Rails will silently complain about what you've done, and next time you reset your database you will be missing something, something probably crucial.
To alleviate that, you can lock yourself into the current database engine and dump out structure.sql
which is a database-specific set of SQL instructions. Just add this to your config/application.rb
:
Voila! Next time you run your migrations, your schema.rb
will be replaced with a nifty structure.sql
.
If you are running your application in a Docker container and need to run migrations on it for some reason, keep in mind that Rails will error out unless you also package the database dumping tool for your database (e.g. pg_dump
) alongside your app.
Unlike Postgres, Rails is not concerned with the integrity and consistency of your database. Rails will happily spew null
values everywhere and skip over your callbacks if you confuse delete
and destroy
. You can use the amusingly named to automatically find missing indices and foreign constraints, but you should also know how to do it manually.
For any relationship between models, you should have a foreign key in your migration. This is very easy to accomplish when creating a migration:
In this example, we're creating a posts
table that references the id
field on user
table via the user_id
field on the posts
table. The dependent: :delete
part means we want our posts to be deleted if a user is also deleted, thus preventing us from having posts whose author is nil
. Since it's enforced by the database, there is no way to have a post assigned to a user that does not exist.
Another useful thing that you might have noticed is the null: false
part. This ensures that a value must exist when creating a field, thus enforcing a validates :field, presence: true
instruction on a model. You should also enforce your uniqueness
constraints by adding a unique index on a field (or a combination of fields, if you want scoped uniqueness constraints!)
Read more about this on the Rails guide:
Everything you need to know about all of those things is in this table. Types with an asterisk (*) are Rails specific.
Ruby / Rails class
Migration
Postgres Equivalent
What it does
Date
:date
date
It's a date, without time.
Example: 2019-01-01
Time
:datetime
timestamp
Amusingly, Time
is a date with a time.
Example: 2019-01-01 00:00:00
TimeWithZone*
:datetime
timestamp with time zone
Rails automatically decides to convert datetime formats to a format with a time zone.
DateTime
none
none
It's like Time, but with better date arithmetic and less precision.
Duration*
none
interval
If you want to express abstract times like 3 hours
, this is the type for you.
If you're really hardcore, you can also use for other basic validation, thus ensuring the value of a field is what you'd expect.