くりにっき

フルスタックキュアエンジニアです

【今月のgem】activerecord-compatible_legacy_migration というgemを作った

github.com

どんなgemか

同一のmigrationファイルでRails 4.2系とRails 5.0系の両方でいい感じに動くようにするためのgemです

これだけだと分かりづらいので具体例を出します

Rails 4.2系から5.0系へのmigrationファイルの移行について

Rails 4.2系から5.0系に移行する時に、Rails 4.2で作られた既存のmigrationのスーパークラスを下記のように ActiveRecord::Migration から ActiveRecord::Migration[4.2] にします

Rails 4時代のmigration

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.timestamps null: false
    end
  end
end

Rails 5移行後のmigration

class CreateUsers < ActiveRecord::Migration[4.2]
  def change
    create_table :users do |t|
      t.timestamps null: false
    end
  end
end

ActiveRecord::Migration のままでもエラーにはなりませんがログファイルに下記のようなDEPRECATION WARNINGが出ます *1

DEPRECATION WARNING: Directly inheriting from ActiveRecord::Migration is deprecated. Please specify the Rails release the migration was written for:

class CreateUsers < ActiveRecord::Migration[4.2]

ユースケース

アプリであればmigrationファイルを上記のように修正すればいいのですが、moutable engineのようにgemの中に内包されてるmigrationファイルをアプリの db/migrate/ にコピーするgemだとそうはいきません。

  • gem内のmigrationファイルが ActiveRecord::Migration の場合
    • アプリでRails 4.2系を使ってる時は問題なし
    • アプリでRails 5.0系を使ってる時にDEPRECATION WARNINGが出る
      • 動きはするけど、5.1辺りで使えなくなる可能性もあるのでできれば放置はしたくない
      • とはいえgem開発者的にはなるべく多くのバージョンに対応しておきたい
      • アプリでmigrationファイルを修正後にgemのmigration installコマンドをたたいた時にgem側のmigratonファイルとアプリ側のmigratonファイルで差分があると「変更されてるけど上書きしますか?」的な確認が大量にでそう(自信ない)
  • gem内のmigrationファイルが ActiveRecord::Migration[4.2] の場合
    • アプリでRails 5.0系を使ってる時は問題なし
    • アプリでRails 4.2系を使ってる時にはエラーになる

migrationファイルを内包したgemをいくつかメンテしているのですが、Rails 5対応をするために既存のRails 4系のアプリともmigrationファイルの互換性を保つのが割とつらかったのでそれを解決するために作りました

使い方

migrationクラスのスーパークラスActiveRecord::CompatibleLegacyMigration.migration_class にするだけです

class CreateUsers < ActiveRecord::CompatibleLegacyMigration.migration_class
  def change
    create_table :users do |t|
      t.timestamps null: false
    end
  end
end

ActiveRecord::CompatibleLegacyMigration.migration_classRails 5.0以降だと ActiveRecord::Migration[4.2] を、Rails 5未満だと ActiveRecord::Migration を返します

https://github.com/sue445/activerecord-compatible_legacy_migration/blob/v0.1.0/lib/active_record/compatible_legacy_migration.rb

Rails 5.0以降でしか使えないmigrationファイルはgemとして配布する時に ActiveRecord::Migration[5.0] つければいいと思います

おまけ

他のgemはどうやってRails 5対応やってるんだろうなぁと思って試しに devise を見たら [5.0] の部分をerbで埋め込んでた

gemごとに個別対応するの、つらみある。。。

最後に

gemでmigrationファイルを配布していてRails 4.2系とRails 5.0系を両方メンテする必要が出てきたら是非ご利用ください

*1:コンソールには出ないので注意