# Contains the enhancements to Rails' migrations system to support the
# Engines::PluginMigrator. See Engines::RailsExtensions::Migrations for more
# information.
require "engines/plugin_migrator"
# = 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
# Rails.plugins[:tagging].migrate(3)
# end
# def self.down
# Rails.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
# Rails.plugins[:tagging].migrate(5)
# end
# def self.down
# Rails.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:
#
# Rails.plugins[:whatever].migrate(version)
#
# ---
#
# The Engines::RailsExtensions::Migrations module defines extensions for Rails'
# migration systems. Specifically:
#
# * Adding a hook to initialize_schema_information to create the plugin schema
# info table.
#
module Engines::RailsExtensions::Migrations
def self.included(base) # :nodoc:
base.class_eval { alias_method_chain :initialize_schema_information, :engine_additions }
end
# Create the schema tables, and ensure that the plugin schema table
# is also initialized. The plugin schema info table is defined by
# Engines::PluginMigrator.schema_info_table_name.
def initialize_schema_information_with_engine_additions
initialize_schema_information_without_engine_additions
# create the plugin schema stuff.
begin
execute <<-ESQL
CREATE TABLE #{Engines::PluginMigrator.schema_info_table_name}
(plugin_name #{type_to_sql(:string)}, version #{type_to_sql(:integer)})
ESQL
rescue ActiveRecord::StatementInvalid
# Schema has been initialized
end
end
end
::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, Engines::RailsExtensions::Migrations)
# Set ActiveRecord to ignore the plugin schema table by default
::ActiveRecord::SchemaDumper.ignore_tables << Engines.schema_info_table