その他
    ホーム技術発信DoRubyRailsのgeneratorでMultiple migrationsとなる件の対応方法

    RailsのgeneratorでMultiple migrationsとなる件の対応方法

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    Railsのgeneratorでmigrationが二つ以上ある時の対策をしました。

    Railsのgenerator対応のプラグインを作成している時に、migrationが二つ以上あるとdb:migrateに失敗してしまいます。

    エラーの内容は以下のとおりです(一部伏せています)。

    bash-3.2$ script/generate xxx_payment -f XxxPayment
          exists  app/models/
          exists  config/initializers/
          exists  spec/controllers/
          exists  spec/factories/
           force  app/models/xxx_payment_plugin.rb
          create  app/models/xxx_payment_results.rb
       identical  config/initializers/xxx_payment_cart_controller_extend.rb
           force  spec/controllers/xxx_cart_controller_spec.rb
           force  spec/factories/xxx_payments.rb
          exists  db/migrate
          create  db/migrate/20100831124224_create_xxx_payment_plugins.rb
          exists  db/migrate
          create  db/migrate/20100831124224_create_xxx_payment_results.rb
    bash-3.2$ rake db:migrate
    (in /Users/btm/develop/elecoma/devel_git)rake aborted!
    Multiple migrations have the version number 20100831124224
    (See full trace by running task with --trace)
    

    このように二つのmigrationが同じ日付になっているため、「Multiple migrations have the version number」となってしまうのです。

    では、対策をしてみましょう。実際のところ、時間の取り出しはnext_migration_stringというメソッドで行われているようです。

    # rails-2.3.5/lib/rails_generator/commands.rb
              def next_migration_string(padding = 3)
                if ActiveRecord::Base.timestamped_migrations
                  Time.now.utc.strftime("%Y%m%d%H%M%S")
                else
                  "%.#{padding}d" % next_migration_number
                end
              end
    

    結局のところ、Time.nowのタイミングをずらせばよいというのがわかります。

    なので、generatorでは以下のように書けばOKです。

    # xxx_payment_generator.rb
    class XxxPaymentGenerator < Rails::Generator::NamedBase
      default_options :skip_migration => false
    
      ...
      def manifest
        record do |m|
          ...
          # migration
          # migration
          unless options[:skip_migration]
            m.migration_template 'create_xxx_payment_plugins.rb', 
                                 'db/migrate', 
                                 :assigns => {}, 
                                 :migration_file_name => "create_xxx_payment_plugins"
            m.sleep 1
            m.migration_template 'create_xxx_payment_results.rb', 
                                 'db/migrate', 
                                 :assigns => {}, 
                                 :migration_file_name => "create_xxx_payment_results"
          end
          ...
        end
      end
    end
    

    m.migration_template 同士の間に “m.sleep 1 “として一秒間ずらしてあげます。

    では、作成してみましょう。

    bash-3.2$ script/generate xxx_payment -f XxxPayment
          exists  app/models/
          exists  config/initializers/
          exists  spec/controllers/
          exists  spec/factories/
       identical  app/models/xxx_payment_plugin.rb
       identical  app/models/xxx_payment_results.rb
       identical  config/initializers/xxx_payment_cart_controller_extend.rb
       identical  spec/controllers/xxx_cart_controller_spec.rb
       identical  spec/factories/xxx_payments.rb
          exists  db/migrate
          create  db/migrate/20100831131456_create_xxx_payment_plugins.rb
          exists  db/migrate
          create  db/migrate/20100831131457_create_xxx_payment_results.rb
    

    Versionが一つずれて作成されているのがわかります。これで、無事マイグレートができるようになりました。

    同じエラーではまった人は参考にしていただけると幸いです。