Continuing exploring ActiveRecord without Rails, I thought I’d look into using Migrations without Rails.
Once again, why?
- You already are using ActiveRecord without Rails
- Versionable instances of how your database looked like
- Database agnostic
- You forget how to crack out SQL code (happens to me, maybe too much ORM)
- You want migrations in non Ruby Projects
One thing I’d like to emphasize is that you don’t have to use Migrations for Ruby Projects. You can use them in non Ruby projects as well. Just use them to create a versioned of the database.
By using Migrations, your (Ruby and non Ruby) developers will appreciate that they can easily see what changes were made to the database.
- I won’t go into getting ActiveRecord working without Rails, please refer to that post. It’s dead simple.
- All these commands are executed from the root directory of your non-rails application.
Creating the Migrations Directory
First we need a directory where the migrations will be stored, in this case I’ll use the name ‘
mkdir -p db/migrate
Now we’ll create our first migration, and save it as
class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.column :name, :string, :null => false end end def self.down drop_table :users end end
- The numbers prefixed to the migration file’s name (in this case 001) are very important. DO NOT OMMIT THIS.
- Notice the class name is CreateUsers, this should correspond to a camel case representation of the filename.
Setting up the Rakefile
Now we’ll need a Rakefile. If your not familiar with Rakefiles just create a file called:
require 'active_record' require 'yaml' task :default => :migrate 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 ) end task :environment do ActiveRecord::Base.establish_connection(YAML::load(File.open('database.yml'))) ActiveRecord::Base.logger = Logger.new(File.open('database.log', 'a')) end
:environment task sets up the ActiveRecord configurations, configure as desired.
Your First Migration
Executing the migration is dead easy:
If you chose to log the output you’d get something like this:
SQL (0.004480) CREATE TABLE schema_info (version integer)
SQL (0.001514) INSERT INTO schema_info (version) VALUES(0)
SQL (0.000000) SQLite::Exceptions::SQLException: table schema_info already exists: CREATE TABLE schema_info (version integer)
SQL (0.000246) SELECT version FROM schema_info
Migrating to CreateUsers (1)
== CreateUsers: migrating =====================================================
SQL (0.002094) CREATE TABLE users (“id” INTEGER PRIMARY KEY NOT NULL, “name” varchar(255) NOT NULL)
== CreateUsers: migrated (0.0028s) ============================================
SQL (0.001499) UPDATE schema_info SET version = 1
Note: I am using SQLite in this example, your results may come out differently.
Your Second Migration
Knowing that our first migration works, lets create a second migration and test it out!
Now let’s create another migration:
class CreateRoles < ActiveRecord::Migration def self.up create_table :roles do |t| t.column :name, :string, :null => false end end def self.down drop_table :roles end end
And when executing
rake , you should see the new table roles being created!
Moving Between Versions
At this stage we are at at version 2 of the database. But how do we go down to say version 0, before everything existed?
What? You only want to go to version 1?
Okay, enough showing off
That’s it, your ready to use and enjoy ActiveRecord’s Migrations Without Rails!
The Migration’s have a ton of features which you can and should utilize, which including adding indexes, controlling verbosity, renaming tables, dropping tables, and modifying existing tables (adding, renaming, modifying, deleting columns).
Just a whole alot of features, do check out the API for it!