Migrations in Rails Engine?
I have multiple rails applications talking to the same backend and I'd like them to share some migrations.
I setup a rails e开发者_StackOverflow社区ngine (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 !
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
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.
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.
精彩评论