Rails 7.1 db:prepare to load schema if the database already exists but is empty
source link: https://blog.saeloun.com/2023/02/02/rails-allow-db-prepare-to-load-schema-if-database-exists
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
What is rails db:prepare?
In Rails 6.1, the rails db:prepare
command was introduced to prepare the database for use.
This command idempotently sets up a database (creating the database, loading schema, and/or migrations).
Presently, if the database exists
and has tables that are not populated,
db:prepare will run all the migrations
to bring the database up to the state.
This may not be ideal in situations
where we might have pruned old migration files,
or if the database is provisioned
by a Platform as a Service (PaaS) provider.
During initial setup, PaaS providers provision an empty database.
Running db:prepare will run all the migrations
which may not be as efficient as loading the schema.
Before
Let’s assume in our Rails application we have two migrations,
one to create model Product
and another to create model User
.
# Generate the model for Product
rails g model Product title:string
# Prepare the database
rails db:prepare
== 20230201061344 CreateProducts: migrating ======================================
-- create_table(:products)
-> 0.0027s
== 20230201061344 CreateProducts: migrated (0.0028s) =============================
# Drop the database
rails db:drop
Dropped database 'rails-7-demo_development'
# Generate the model for User
rails g model User name:string
# Prepare the database
rails db:prepare
== 20230201061344 CreateProducts: migrating ======================================
-- create_table(:products)
-> 0.0019s
== 20230201061344 CreateProducts: migrated (0.0021s) =============================
== 20230201061529 CreateUsers: migrating ====================================
-- create_table(:users)
-> 0.0015s
== 20230201061529 CreateUsers: migrated (0.0016s) ===========================
In the above example, after dropping the database,
we generated a new model User
,
and ran the rails db:prepare
command.
This command ran both migrations,
even though the database was empty.
After
However in the upcoming Rails 7.1,
if we were to run the same commands,
the rails db:prepare
command will load the schema
and run the remaining migrations.
# Generate the model for Product
rails g model Product title:string
# Prepare the database
rails db:prepare
== 20230201061344 CreateProducts: migrating ======================================
-- create_table(:products)
-> 0.0027s
== 20230201061344 CreateProducts: migrated (0.0028s) =============================
# Drop the database
rails db:drop
Dropped database 'rails-7-demo_development'
# Generate the model for User
rails g model User name:string
# Prepare the database
rails db:prepare
== 20230201061529 CreateUsers: migrating ====================================
-- create_table(:users)
-> 0.0015s
== 20230201061529 CreateUsers: migrated (0.0016s) ===========================
In the above example,
after dropping the database,
when rails db:prepare is run,
it only runs the migration to create the User
model.
However, if we were to look at the schema, we would see that both tables are present.
ActiveRecord::Schema.define(version: 2021_02_03_061529) do
create_table "products", force: :cascade do |t|
t.string "title"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
end
This is because the rails db:prepare
command will now load the schema
and then run the remaining migrations.
If the database exists but is empty, the rails db:prepare
command will simply load the schema without running any migrations
# Generate the model for Product
rails g model Product title:string
# Prepare the database
rails db:prepare
# Drop the database
rails db:drop
# Create the database
rails db:create
# Prepare the database
rails db:prepare
# There will be no output since no migrations will be run
# Schema.rb
ActiveRecord::Schema.define(version: 2021_02_03_061529) do
create_table "products", force: :cascade do |t|
t.string "title"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
end
This change is achieved by using the value of ActiveRecord::SchemaMigration.table_exists?
to determine if the database has been populated with tables.
If the value is false,
the db:prepare task will load the schema,
and then run any remaining migrations.
Else, db:prepare will continue to work as it did.
Check out the PR for more details.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK