Ruby rails: migrations
Migrations allow you to version your database schema independently of it's data.
Database Migrations are reversible, for example new data can be ported to an old schema if you revert a database migration.
There are two general types of migrations.
- migrations (add column, etc.)
- maintenance_tasks (backfills, etc.)
Documentation
official docs https://guides.rubyonrails.org/active_record_migrations.html change methods
ActiveRecord::ConnectionAdapters::SchemaStatementshttps://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html
Locations
{project}/db/migrate/{datetime}_{job_snakecase}.rb
database migration files {project}/app/jobs/maintenance/{job_snakecase}_task.rb
maintenance-task files test/maintenance/{job_snakecase}_task_test.rb
maintenance-task tests
Commandline
rails db:migrate \ # run all un-run migrations VERSION=20090408054532 # optionally specify exact migration rails db:rollback # roll back the last migration rails generate migration 'YourMigrationName' # generate a migration rails generate maintenance_task 'YourMaintenanceTaskName' # generate maintenance_task
Database
In the database, when your migration completes,
a row is inserted into the tableschema_migrations
with the version (ex:20090408054532
) to indicate that it has run.
It will not run again.
Example
# {project}/db/20140120191729_create_articles.rb class CreateArticles < ActiveRecord::Migration[6.0] def change create_table :articles do |t| # ':articles' is database table name t.belongs_to :author t.string :title t.text :text t.timestamps # 'timestamps' is macro, creates 'created_at', 'updated_at' columns end end end
Change operations
Change operations are automatically reversible (eg. you don't need to define up/down methods for these).
See docs at https://api.rubyonrails.org/?q=Migration for a complete list of supported changes.class ChangeUserTable < ActiveRecord::Migration[5.0] def change add_column(:table, :column, :string) # aditional options optional add_index(:table, :column) remove_column(:table, :column) rename_column(...) change_column :age, null: true execute("UPDATE `table` SET id = 1 WHERE id = 2;") end end
Reversible (Complex Changes)
Active Record can generally manage simple changes, like column-names or datatype changes.
If you need to do make complex change, you can inform rails how to reverse it.See which operations require a
down
method here https://edgeguides.rubyonrails.org/active_record_migrations.html#using-the-change-method .class ChangeProductsPrice < ActiveRecord::Migration[5.0] def change reversible do |dir| change_table :products do |t| dir.up { t.change :price, :string } # when applied dir.down { t.change :price, :integer } # when reverted end end end end
Transactions
NOTE:
If your rails app is using connections to multiple databases,
you should be explicit and useModel.transaction do
instead of
the genericActiveRecord::Base.transaction do
Transactions can be opened from any model.
They are not specific to that model, but the database connection used by that model.
You do not need a separate transaction for each model.
See http://vaidehijoshi.github.io/blog/2015/08/18/safer-sql-using-activerecord-transactions/ActiveRecord::Base.transaction do # your sql end # or YourModel.transaction do # your sql endYou can force a rollback with
raise ActiveRecord::Rollback