What is the use of the Schema.rb file? - ruby-on-rails

What exactly is the use of the Schema.rb file?

It is a generated file when you run your migrations. To the best of my knowledge it has two uses:
Your database schema is in one place and can be viewed and reviewed.
You can load your database in one shot by use rake db:schema:load instead of having to walk through your migrations

This file is reproduced every time you execute a migration. It reproduces the entire schema of your database. It is also used by certain commands in migration in Rails to avoid redoing all the migrations one by one (in the case of a migration reset for instance).
It is also the only place when you can see all your tables at once for the reference of columns. But I suggest you to use the gem annotate in order to document your models with all column names. It's easier to work like this than having to go to schema.rb everytime you want details about the DB structure of your model.

One good usage of schema.rb is whenever we run rake test, it prepares the test database instantly using schema.rb(without running the migrations).

Related

How can I convert all migration files into a single file in Rails?

I have been developing a project in Ruby on Rails. During the development I have generated tons of migration files for my project. Sometimes I have added and deleted columns from different tables.
Is there a way that I could consolidate all the migrations from multiple files into a single file?
TL;DR
What you need isn't a consolidated set of migrations; it's a single schema file and an optional seeds.rb file. Rails generally maintains the schema automagically when you run migrations, so you already have most of what you should need with the possible exception of seed data as described below.
Use the Schema, Not Migrations
In general, you shouldn't be maintaining a large pool of migrations. Instead, you should periodically clear out your migrations, and use schema.rb or schema.sql to (re)create a database. The Rails guides specifically state:
There is no need (and it is error prone) to deploy a new instance of an app by replaying the entire migration history. It is much simpler and faster to just load into the database a description of the current schema...Because schema dumps are the authoritative source for your database schema, it is strongly recommended that you check them into source control.
You should therefore be using bin/rails db:schema:load rather than running migrations, or run the associated Rake task on older versions of Rails.
Data Migrations
While you can use migrations to fix or munge data related to a recent schema change, data migrations (if used at all) should be temporary artifacts. Data migrations are almost never idempotent, so you shouldn't be maintaining data migrations long-term. The guide says:
Some people use migrations to add data to the database...However, Rails has a 'seeds' feature that should be used for seeding a database with initial data. It's a really simple feature: just fill up db/seeds.rb with some Ruby code, and run rake db:seed...This is generally a much cleaner way to set up the database of a blank application.
Database seed data should be loaded with bin/rails db:seed (or the associated Rake task) rather than maintaining the data in migrations.
There is a gem that purports to do exactly what you describe in the question - check out Squasher.
From the README:
"Squasher compresses old migrations in a Rails application. ... Squasher removes all the migrations and creates a single migration with the final database state of the specified date (the new migration will look like a schema)."
You'll have to do the merge manually.
But if you want only a single file, there is db/schema.rb. It contains a snapshot of current database schema. You can load it directly in database if you want.

Build db:rake task from existing Database

I have a project that has had alot of editing to the postgresql database.
I am tring to find out is there a way to build a new db:rake file so i can rebuild the database on new server easily. Without manually editing the db:rake files.
thanks
Ruby 1.9.3
CentOS 6.4
Ruby on Rails 3
postgresql 9.3
For clarity, I am assuming you are referring to the migration files when you mention db:rake files.
In Rails, you don't want to rebuild the database using migration files. They can quickly become outdated, referring to things that no longer exist, etc. Instead, it is best practice to recreate the database using your schema.rb file instead. This is touched on an answer I wrote a while back. In short, the schema.rb file represents your database table structure; a snapshot, if you will. Note that it does not contain data, only the table structure.
In your scenario, in order to create, or ensure your schema.rb is up to date, you simply need to dump the schema, like so:
rake db:schema:dump
This regenerates the schema.rb file. Then, to rebuild the database from this file in another environment, simply reload the schema, like so:
rake db:schema:load
As stated above, the schema.rb does not contain any data from the tables, it merely represents the structure. If you want to preload the database with initial / default values, you will want to use the seed.rb file. Simply write your .create statements, and run it like so:
rake db:seed

Rails - autogenerate migrations from database changes

Is it possible to use Rails to auto-generate a migration based on changes that took place in the database outside of Rails since the last migration?
I know that running db:migrate will change the schema.rb to match what's in the database.... (at least if don't make any migrations but I do change the database in some way manually). What I'm wondering is, if there is a way as part of that same mechanism or process to have it create a migration out of those changes.
Many thanks!
I don't think this is something Rails would do or is trying to solve. Rails wants you to explicitly manage those changes through migrations so that your database is under control (and source control).
See if this gem is what you want. - https://github.com/pjhyett/auto_migrations
It might not work with Rails 3. I think since you edit your DB directly you'd have to run rake db:schema:dump to update the schema.rb file.
If you want to capture the deltas between the different db change points then see this SO answer:
How to generate Rails Migration class automatically from MYSQL database instance? , just repeat his steps along the way.

Why is db:reset different from running all migrations?

In section Rails Database Migrations of Ruby on Rails Guides, there is one line saying that
The db:reset task will drop the database, recreate it and load the current
schema into it. This is not the same as running all the migrations.
Can anyone tell me where exactly they are different and why it is more error prone to replay the migration history?
I'm fairly new to Ruby on Rails. Thanks in advance.
The schema file contains the current structure of your database. When you load it, you are guaranteed to have the exact schema in your db that is in the file. Migrations were designed to make incremental changes in the database. You may add a table, then some columns, and then remove the table in three separate migrations. There's no need to go through all this when the schema already knows that the table no longer exists.
On why they are error prone, I'm not totally sure. The one thing I can think of is that migrations can be used to make changes to data and not just the structure.
Running rake db:reset will rebuild the structure of your database from schema.db, which essentially works as a cached version of your migrated database structure. Running all your migrations, on the other hand, applies the migrations one by one, which may include arbitrary code to accomodate for changes to the database (e.g. prepopulate an added counter cache column).
It can be more error prone to replay the migration history, since it is the product of changes to both the structure and data of the database. If the developers haven't been careful, it might not apply cleanly to a fresh environment (e.g. the migration assumes an old version of a model). On the other hand, schema.db can get out of sync if you edit a migration once you've migrated (a useful trick to avoid migration explosion during development). In that case, you need to run rake db:migrate:reset.

Aggregate migrations in Rails

I have several dozens Rails DB migrations which were written over a year. Is there a way to aggregate them to one migration so that I will just see a full DDL statement for the database as it exists now? I just need the current snaphot without all the history of how we got to it.
It is possible, but probably not a good idea to aggregate the migrations!
Maybe ask:
Why do you want to do this?
How often do you really need to migrate all the way to VERSION=0 and then back up again?
Is something really broken? (if not, then don't fix it)
I've had the same problem once.. I ended up just re-ordering my migrations, because changes in the schema caused it to not correctly migrate up/down anymore. I would be hesitant to do that again.
If you have migrations which just add fields or indexes, then maybe you can combine them with the main migration for the model -- but beware that you can't reproduce old situations anymore, e.g. older DB-dumps may not be compatible with what migration number they should be compatible with -- that is probably the biggest argument against aggregating...
Technically, you can dump the schema and then load it directly - that is one way:
rake db:schema:dump
then create a single new migration with the contents of the schema dump file db/schema.rb
Here are some similar questions:
Rebase Rails migrations in a long running project
Deleting/"Rebasing" rails migrations
Way to "flatten" Rails migrations?
Should I flatten Rails migrations?
P.S.: I found it useful to stick with the old migration numbering scheme, where the migrations do not use timestamps - for me this works better (is easier to see in which order they are).
e.g. in your config/application.rb file:
config.active_record.timestamped_migrations = false
You should never be using all the migrations to get a database up and running. The current schema.rb is always what the DB looks like 'presently'.
It's good practice to periodically just truncate your migrations if you have a ton of them in there. We finally did that with one of our larger applications, removing a good 50 migrations from the folder because the only thing that matters is schema.rb. Migrations are just that, a way to migrate and make changes to an existing state of the database. They should only ever have to be run once.
You can simply load the current schema into the DB.
rake db:schema:load RAILS_ENV=[production, test, etc.]
This will take the schema.rb file's version of the schema, and load it into the DB without running individual migrations.
NOTE: if you have migrations that put data into the DB (e.g. default values, for example), that data will not be added to the DB.
If you need to load default values into your DB, that might be better done via a custom rake task, independent of migrations.

Resources