Why do Rails Migrations cause the database schema to be dumped into schema.rb?

Have you ever wondered why rake db:migrate took so long to complete when you ran a simple migration script? The reason is that it's dumping your database's entire schema into db/schema.rb just like rake db:schema:dump does.

I had to get to the bottom of why this was happening and searching the internet was not providing any answers, so I took to searching the Rails codebase to see if I could find any clues.

databases.rake in /usr/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/tasks/ showed the root cause:

namespace :db do
desc "Migrate the database through scripts in db/migrate. Target specific version with VERSION=x"
task :migrate => :environment do
ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
If the 'schema_format' is set to':ruby' then run the rake task 'db:schema:dump' after we have finished running the migrations. But where is schema_format set? A look in config/environment.rb gave a clue:
  # Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
This configuration value is commented out and indicates that if this is enabled then the schema dumps will be in SQL format rather than the more portable (and in my mind preferable) Ruby format.

base.rb in /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/ gave the final clue:
    # Specifies the format to use when dumping the database schema with Rails'
# Rakefile. If :sql, the schema is dumped as (potentially database-
# specific) SQL statements. If :ruby, the schema is dumped as an
# ActiveRecord::Schema file which can be loaded into any database that
# supports migrations. Use :ruby if you want to have different database
# adapters for, e.g., your development and test environments.
cattr_accessor :schema_format , :instance_writer => false
@@schema_format = :ruby
So base.rb sets the schema_format variable to be ruby and therefore enables the automatic dumping of the schema after every migration.

Now I just have to figure out how to disable it...

Update: I've figured out a way to disable schema.rb from being generated.

Technorati Tags: , , , , ,


Anonymous said...

careful - rake test uses schema.rb to create the test db and then loads the fixture data into it.

Nostrum Forder said...

And - the schema dump code that creates schema.rb is faulty. If you set :id => false in the table creation and then create a field called "id" that's not the same spec as the AR Migrations default primary key spec for your table, schema.rb will blithely create an "id" field with the AR default spec, and you'll have tests that fail and fixtures that won't work.

Steve Madsen said...

You should reconsider disabling the schema dump. It is recommended to check schema.rb (or development_structure.sql) into your source control system and use it, and not the historical migrations, to build up a new database.

Migrations are great for incremental changes, but they are fragile and will often break if you reference models directly from them.