Question

I have multiple rails applications talking to the same backend and I'd like them to share some migrations.
I setup a rails engine (with enginex), I can share anything (controllers, views, models,...) but no migrations. I can't make it work !

I tried to create a file db/migrate/my_migration.rb but in my main application if I do :

  rake db:migrate

It doesn't load them.

After some googling it appears there was some recent work on this and it seems this has been merge to rails master. I'm with rails 3.0.3 do you see any way to make this work ?

Thanks !

Was it helpful?

Solution

What i do, is add an InstallGenerator that will add the migrations to the Rails site itself. It has not quite the same behavior as the one you mentioned, but for now, for me, it is good enough.

A small how-to:

First, create the folder lib\generators\<your-gem-name>\install and inside that folder create a file called install_generator.rb with the following code:

require 'rails/generators/migration'

module YourGemName
  module Generators
    class InstallGenerator < ::Rails::Generators::Base
      include Rails::Generators::Migration
      source_root File.expand_path('../templates', __FILE__)
      desc "add the migrations"

      def self.next_migration_number(path)
        unless @prev_migration_nr
          @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
        else
          @prev_migration_nr += 1
        end
        @prev_migration_nr.to_s
      end

      def copy_migrations
        migration_template "create_something.rb", "db/migrate/create_something.rb"
        migration_template "create_something_else.rb", "db/migrate/create_something_else.rb"
      end
    end
  end
end

and inside the lib/generators/<your-gem-name>/install/templates add your two files containing the migrations, e.g. take the one named create_something.rb :

class CreateAbilities < ActiveRecord::Migration
  def self.up
    create_table :abilities do |t|
      t.string  :name
      t.string  :description
      t.boolean :needs_extent      
      t.timestamps
    end
  end

  def self.down
    drop_table :abilities
  end
end

Then, when your gem is added to some app, you can just do

rails g <your_gem_name>:install

and that will add the migrations, and then you can just do rake db:migrate.

Hope this helps.

OTHER TIPS

In rails 3.1, you can do it using this command, give that your engine name is example:

# Note that you append _engine to the name
rake example_engine:install:migrations

Under 3.1, you can share migrations, without installing them, by altering config/application.rb to do something like this:

# Our migrations live exclusively w/in the Commons project
config.paths['db/migrate'] = Commons::Engine.paths['db/migrate'].existent

As of Rails 3.1 looks like the solution is:

bundle exec rake railties:install:migrations

If you only want to copy from a specific railtie then:

bundle exec rake railties:install:migrations FROM=foo_engine

Note the name is whatever you gem is named plus _engine. So if the gem is "foo" then the name is foo_engine.

For rails 4 use:

   initializer :append_migrations do |app|
      unless app.root.to_s.match root.to_s
        config.paths["db/migrate"].expanded.each do |expanded_path|
          app.config.paths["db/migrate"] << expanded_path
        end
      end
    end

https://content.pivotal.io/blog/leave-your-migrations-in-your-rails-engines

To go off of Levi's answer you could also do something like this in your engine file in the actually engine, instead of the application.

So in lib/commons/engine.rb

module Commons
  class Engine < Rails::Engine
    initializer "commons.load_app_instance_data" do |app|
      Commons.setup do |config|
        config.app_root = app.root
      end
      app.class.configure do 
        #Pull in all the migrations from Commons to the application
        config.paths['db/migrate'] += Commons::Engine.paths['db/migrate'].existent
      end
    end
    initializer "commons.load_static_assets" do |app|
      app.middleware.use ::ActionDispatch::Static, "#{root}/public"
    end
  end
end

Edit: Be careful though to not mess up people migration history after doing this, make sure you add a new migration if a change is needed, otherwise you might force someone to do some ugly rollbacks.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top