Module: Engines::RailsExtensions::Migrations

Included in:
ActiveRecord::ConnectionAdapters::SchemaStatements
Defined in:
lib/engines/rails_extensions/migrations.rb

Overview

Plugins and Migrations: Background

Rails uses migrations to describe changes to the databases as your application evolves. Each change to your application - adding and removing models, most commonly - might require tweaks to your schema in the form of new tables, or new columns on existing tables, or possibly the removal of tables or columns. Migrations can even include arbitrary code to transform data as the underlying schema changes.

The point is that at any particular stage in your application’s development, migrations serve to transform the database into a state where it is compatible and appropriate at that time.

What about plugins?

If you want to share models using plugins, chances are that you might also want to include the corresponding migrations to create tables for those models. With the engines plugin installed, plugins can carry migration data easily:

vendor/
  |
  plugins/
    |
    my_plugin/
      |- init.rb
      |- lib/
      |- db/
          |-migrate/
              |- 001_do_something.rb
              |- 002_and_something_else.rb
              |- ...

When you install a plugin which contains migrations, you are undertaking a further step in the development of your application, the same as the addition of any other code. With this in mind, you may want to ‘roll back’ the installation of this plugin at some point, and the database should be able to migrate back to the point without this plugin in it too.

An example

For example, our current application is at version 14 (according to the schema_info table), when we decide that we want to add a tagging plugin. The tagging plugin chosen includes migrations to create the tables it requires (say, tags and taggings, for instance), along with the models and helpers one might expect.

After installing this plugin, these tables should be created in our database. Rather than running the migrations directly from the plugin, they should be integrated into our main migration stream in order to accurately reflect the state of our application’s database *at this moment in time*.

$ script/generate plugin_migration
      exists  db/migrate
      create  db/migrate/015_migrate_tagging_plugin_to_version_3.rb

This migration will take our application to version 15, and contains the following, typical migration code:

class MigrateTaggingPluginToVersion3 < ActiveRecord::Migration
  def self.up
    Engines.plugins[:tagging].migrate(3)
  end
  def self.down
    Engines.plugins[:tagging].migrate(0)
  end
end

When we migrate our application up, using rake db:migrate as normal, the plugin will be migrated up to its latest version (3 in this example). If we ever decide to migrate the application back to the state it was in at version 14, the plugin migrations will be taken back down to version 0 (which, typically, would remove all tables the plugin migrations define).

Upgrading plugins

It might happen that later in an application’s life, we update to a new version of the tagging plugin which requires some changes to our database. The tagging plugin provides these changes in the form of its own migrations.

In this case, we just need to re-run the plugin_migration generator to create a new migration from the current revision to the newest one:

$ script/generate plugin_migration
     exists db/migrate
     create db/migrate/023_migrate_tagging_plugin_to_version_5.rb

The contents of this migration are:

class MigrateTaggingPluginToVersion3 < ActiveRecord::Migration
  def self.up
    Engines.plugins[:tagging].migrate(5)
  end
  def self.down
    Engines.plugins[:tagging].migrate(3)
  end
end

Notice that if we were to migrate down to revision 22 or lower, the tagging plugin will be migrated back down to version 3 - the version we were previously at.

Creating migrations in plugins

In order to use the plugin migration functionality that engines provides, a plugin only needs to provide regular migrations in a db/migrate folder within it.

Explicitly migrating plugins

It’s possible to migrate plugins within your own migrations, or any other code. Simply get the Plugin instance, and its Plugin#migrate method with the version you wish to end up at:

Engines.plugins[:whatever].migrate(version)

The Engines::RailsExtensions::Migrations module defines extensions for Rails’ migration systems. Specifically:

  • Adding a hook to initialize_schema_migrations_table to create the plugin schema info table.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



130
131
132
# File 'lib/engines/rails_extensions/migrations.rb', line 130

def self.included(base) # :nodoc:
  base.class_eval { alias_method_chain :initialize_schema_migrations_table, :engine_additions }
end

Instance Method Details

#initialize_schema_migrations_table_with_engine_additionsObject

Create the schema tables, and ensure that the plugin schema table is also initialized. The plugin schema info table is defined by Engines::Plugin::Migrator.schema_info_table_name.



137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/engines/rails_extensions/migrations.rb', line 137

def initialize_schema_migrations_table_with_engine_additions
  initialize_schema_migrations_table_without_engine_additions

  # create the plugin schema stuff.    
  begin
    execute "      CREATE TABLE \#{Engines::Plugin::Migrator.schema_info_table_name} \n        (plugin_name \#{type_to_sql(:string)}, version \#{type_to_sql(:integer)})\n    ESQL\n  rescue ActiveRecord::StatementInvalid\n    # Schema has been initialized\n  end\nend\n"