Миграции в Rails Engine?

У меня есть несколько приложений rails, которые обращаются к одному и тому же бэкэнду, и я бы хотел, чтобы они поделились некоторыми миграциями.
Я устанавливаю движок rails (с enginex), я могу делиться чем угодно (контроллерами, представлениями, моделями, ...), но никаких миграций. Я не могу заставить это работать!

Я попытался создать файл db / migrate / my_migration.rb, но в моем основном приложении, если я это сделаю:

  rake db:migrate

Это их не загружает.

После некоторого поиска в Google выяснилось, что было несколько недавних работать над этим, и кажется, что это было объединено с рельсы мастер. Я использую rails 3.0.3, вы видите, как заставить эту работу работать?

Спасибо !


person Mike    schedule 24.12.2010    source источник
comment
Вот довольно хорошая запись в блоге о движках до 3.1 на тот случай, если вы не можете использовать новейшие игрушки. stubbleblog.com/index.php/2011 / 04 /   -  person jacklin    schedule 17.11.2012


Ответы (6)


Что я делаю, так это добавляю InstallGenerator, который добавит миграции на сам сайт Rails. У него не совсем то же поведение, что вы упомянули, но на данный момент для меня это достаточно хорошо.

Небольшое руководство:

Сначала создайте папку lib\generators\<your-gem-name>\install и внутри нее файл с именем install_generator.rb со следующим кодом:

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

и внутри lib/generators/<your-gem-name>/install/templates добавьте два ваших файла, содержащих миграции, например возьмите тот, что называется 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

Затем, когда ваш драгоценный камень добавлен в какое-либо приложение, вы можете просто сделать

rails g <your_gem_name>:install

и это добавит миграции, и тогда вы можете просто сделать rake db:migrate.

Надеюсь это поможет.

person nathanvda    schedule 18.01.2011
comment
Да, это то, что я делал и с Rails Engines, используя класс настраиваемого генератора для копирования миграций, статических ресурсов, запуска других генераторов в целевом приложении, копирования классов шаблонов и изменения файлов конфигурации целевого приложения. - person justsee; 18.02.2011
comment
Для Rails 3.1 это не понадобится. - person Ryan Bigg; 26.04.2011
comment
Мне любопытно, как вы будете обрабатывать обновления вашего плагина, которые требуют изменений миграции. - person davemyron; 21.07.2011
comment
На самом деле, это совсем не сложно. Добавьте новую миграцию в новую версию gem, снова запустите install-generator: он установит только новые файлы, а механизм миграции rails выполнит все остальное: будут выполняться только новые миграции. - person nathanvda; 22.07.2011
comment
Поскольку мы не на рельсах 3.1, мы поступаем так. - person New Alexandria; 26.01.2012
comment
@nathanvda, я пробую обновление, которое вы описали выше пару лет назад, но получаю. Другая миграция уже называется X на первом, и после этого она не работает. Идеи? - person Jamon Holmgren; 22.03.2013
comment
Ну, тогда я полагаю, что уже есть генератор с именем InstallGenerator для большинства драгоценных камней, который является довольно стандартным. Итак, вы либо расширяете его, либо добавляете новый генератор (переименовываете его). Это помогает? - person nathanvda; 22.03.2013

В rails 3.1 вы можете сделать это с помощью этой команды, указав имя вашего движка example:

# Note that you append _engine to the name
rake example_engine:install:migrations
person Jais    schedule 07.11.2011
comment
Круто, спасибо, Джейс. Небольшое уточнение: в Rails 3.1 первая часть заканчивается на _engine. Например, если ваш движок называется gogo, вы должны запустить rake gogo_engine:install:migrations. - person michaeldwp; 08.05.2012

В версии 3.1 вы можете делиться миграциями, не устанавливая их, изменив config / application.rb, чтобы сделать что-то вроде этого:

# Our migrations live exclusively w/in the Commons project
config.paths['db/migrate'] = Commons::Engine.paths['db/migrate'].existent
person Levi    schedule 03.12.2011
comment
У меня это отлично работало в Rails 3.1.3. Намного более предпочтительный подход, чем другие ответы. Я попытался пойти еще дальше и добавить строку конфигурации непосредственно в сам класс Engine внутри моего драгоценного камня (на одну вещь меньше, что нужно сделать при установке драгоценного камня в новом приложении). Я знаю, что это читается, когда я запускаю db: migrate, поскольку он выдает ошибки, если у меня есть опечатки. Однако как только опечатки были исправлены, rake db:migrate ничего не сделал. - person Jon Garvin; 13.01.2012
comment
Как вы делали, чтобы не указывать путь к базе данных движка в каждом проекте? y добавил эту строку config.paths['db/migrate'] = paths['db/migrate'].existent в основной класс Engine, но ничего не произошло - person JGutierrezC; 21.01.2021

В Rails 3.1 решение выглядит следующим образом:

bundle exec rake railties:install:migrations

Если вы хотите скопировать только с определенного рейса, тогда:

bundle exec rake railties:install:migrations FROM=foo_engine

Обратите внимание, что имя - это то, что у вашего драгоценного камня, плюс _engine. Итак, если гем - «foo», то имя - foo_engine.

person Eric Anderson    schedule 23.08.2011

Для рельсов 4 используйте:

   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

person montrealmike    schedule 12.02.2014
comment
Как вы справляетесь с этим при разработке движка, когда вам нужно запускать задачи в контексте приложения test/dummy, в котором app.root всегда совпадает с root? (Другой комментатор поднял тот же вопрос в том посте Pivotal, но не получил ответа.) - person David Moles; 20.02.2016

Чтобы уйти от ответа Леви, вы также можете сделать что-то подобное в файле вашего движка в собственном движке, а не в приложении.

Итак, в 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

Изменить: будьте осторожны, чтобы не испортить историю миграции людей после этого, убедитесь, что вы добавили новую миграцию, если требуется изменение, иначе вы можете заставить кого-то сделать некоторые уродливые откаты.

person rovermicrover    schedule 26.06.2012
comment
Rails 4 я получаю undefined method + 'для # ‹Rails :: Paths_2 _ ‹----------------` вместо += - person montrealmike; 12.02.2014