Posted at

Rails 5.0系から5.1系にアップデートする手順

業務でRails 5.0系を使っていますが、「そろそろウチもフロント周り綺麗にしたい(フレームワーク入れたい)ねー」って話が挙がりました(現状、特にフレームワークを入れていない)。

そんで、「RailsにUIのフレームを入れるならRails 5.1からwebpacker使えるので、これ使うっきゃないっしょ!」って話になり、Rails5.1系にあげることにしました。

片手間でRailsアップデートプロジェクトを1人で発足して5日ほどやりまして、作業用ブランチ上でひととおり動くようになったので、具体的な手順をまとめました。

みなさんのRailsライフのお役に立てれば幸いです。 :pray:

注意


  • 本番環境への適応はまだやってなくて、作業用ブランチ上でのノウハウです。


    • リソースが足りない中空き時間でチャチャっとやったので、まだ現場が追いついてません。。



  • 本番にも入れたらまた記事を書きます。


前提

基本方針は下記を参考にさせて頂きました!大変参考になりました。 :bow:

永久保存版Railsアップデートガイド

Rails 5.1にスムーズにアップグレードするためにやった6つのこと


①テストを書く

当たり前といえば当たり前ですが、バージョンアップによってどこでどんな不具合が発生するか分からないので、日頃からある程度テストを書いておきましょう。

私の所属する組織では幸いにして基本的な処理に対するテストはあったのでパスしました。


②Rails5.1系で廃止/非推奨となる処理の置き換え

下記を参考にさせて頂きました。


ポイント

全てをくまなくチェックするのは費用対効果がよろしくないので、ざっと調べてやるのが良いかと思います。

あとはまぁ、毎回CIも動かすので、何かあったらそこで引っかかるっしょ、的なね。。


③Gemアップデート

Gemfileのrailsのバージョンを rails '5.0.6' から rails '~> 5.1.6' に書き換えてアップデートを行いました。

アプリケーションへの影響を最小限に収めるなら、 bin/bundle update --conservative rails を実行するのが良いと思います。

が、、、自分の場合はRails以外の既存gemのバージョンが結構古くてコンフリクトが解消できそうになかったので、 bin/bundle update でドカンとやりました。

コンフリクトエラーが起きるたびに bin/bundle update --conservative の後ろにgemを追加していったのですが、7個くらい追加したあたりで、追加済みのgemに対するコンフリクトエラーが出て心が折れました。。

こういう時に備えて、定期的に各gemのアップデートをオススメします。


ポイント


  • Railsのバージョンはガッチリ指定すると既存gemとのコンフリクトで死んじゃう、、という方は ~> 5.1という感じでバージョンの幅を持たせてあげると良いと思います。



  • gemによってはバージョンによりRails5.1系と親和性が低かったり、gemの初期インストール時から一切アップデートしてないgemは大型アップデートによって既存のコードでは動かないこともあるので、バージョンを指定して封印するのもアリ。


    • 目的はRailsのバージョンアップであり、全てのgemを最新にすることではないので、時間やリソースとの相談かと思います。

    • 自分の場合はmysql2/sqlite/rpushを封印しました :innocent:




④Rails 5.1系で追加されたファイルを追加

bin/rails app:update コマンドによりRails 5.1系に適したファイルを入れても良いのだけれど、コレやると既存のファイルとの差分を見るのが面倒なので、RailsDiffを参考にさせて頂きました。

これは各バージョン毎にrails newした際に作られるファイルの差分を家訓できるサイトです。

これを見ながら、Rails5.1での変更を自分たちのプロジェクトに適した形で取り入れました。


⑤Schema再構築

さて、アップデートも終わったのでCI回してみるかなーと思ってたんですが、そもそもCIでスキーマ構築時(bin/rails db:schema:load)に落ちるようになってしまいました。。


こんな感じのエラー

-- add_foreign_key("hogehoge", "users")

rake aborted!
ActiveRecord::MismatchedForeignKey: Column `user_id` on table `hogehoge` has a type of `int(11)`.
This does not match column `id` on `users`, which has type `bigint(20)`.
To resolve this issue, change the type of the `user_id` column on `hogehoge` to be :integer. (For example `t.integer user_id`).

Original message: Mysql2::Error: Cannot add foreign key constraint: ALTER TABLE `hogehoge` ADD CONSTRAINT `fk_rails_ce2f10b32e`
FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`)


原因としてはRails 5.1系からテーブルのidがintからbigintになったためです(マジか..)。

私の場合は既存のschemaファイルを元に bin/rails db:schema:load したので怒られました。

対処法としては、 bin/rails db:migrate:reset を実行して既存のマイグレーションファイルを元にschemaファイルを更新することで対処できます。

詳しくは下記が参考になると思います。

Rails5.1からidカラムがbigintになるのでその対応

ただ、この際に各マイグレーションファイルにRailsのバージョンが指定されている必要があります。

バージョンを指定していないとこんな感じのエラーが出ます。


こんな感じのエラー

rails aborted!

StandardError: An error has occurred, all later migrations canceled:

Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:


なので、過去に作られたマイグレーションファイルに下記のようにRailsのバージョンを記載します。

私の場合、はるか昔に作られていたファイルは全部[4.2] で指定しました(全部調べるのは費用対効果がよろしくない..)。

120ファイルくらいあった...


こんな感じのマイグレーション

class CreateUsers < ActiveRecord::Migration[4.2] #<- こんな感じで'[Railsバージョン]'を指定する

def change
create_table(:users) do |t|
...
end

bin/rails db:schema:load を実行するとschemaファイルが更新され、下記のように id: :integer が追加されます。


schema.rb

create_table "users", id: :integer, force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|

t.string "name", null: false
...


⑥CIをひたすら実行

既存のgemが古い中でもろもろバージョンアップしたので、結構な量のテストが落ちました。

主なエラー原因は下記


  • carrierwave gemによるもの

  • RSpecの記法変更によるもの


    • 元のバージョンが結構古かったので、アップデートにより廃止されたものが多かった



  • アソシエーションの定義順序によるもの


    • モデルでの has_many :through の定義順序が厳しくなったらしく、 ActiveRecord::HasManyThroughOrderError が多発



落ちたテストが全て通るようになったら晴れてRails5.1系が使えます。


webpacker入れてみる

webpackerがちゃんと入るか確認したかったので入れてみました。

既存のRailsアプリにwebpackerを導入する手順としては下記が非常に参考になりました。

【Rails】Webpackerを導入してモダンなJavaScriptをRailsで使う

ひとまず問題なくwebpackerが入ったので一安心!


所感


  • Gemは割と定期的にアップデートしといた方が良い(というか、しとくべき..)。


    • 自分の場合、メジャーバージョンが2つくらい飛んでるgemがあって絶望した..



  • gemのアップデート後のCIでgem起因で落ちるテストがある場合、少し調べて原因不明ならさっさとバージョン固定して封印すべし!


    • これに翻弄されてかなり時間を浪費した..

    • 理想としては全部解決すべきだけど、時間とリソースと相談すべし



  • やってみると案外できるので、まずはやってみること!