[Rails]Railsのバージョンを5.0→5.2に上げてみた

# やりたいこと
Rails5.0系からRails5.2系にバージョンを上げたい。（Rails5.2から使えるようになった[Active Storage](https://railsguides.jp/active_storage_overview.html)を使いたかった。）

この記事の趣旨は、**Rails5.0系からRails5.2系にバージョンを上げるために必要な手順**と**その際に発生したエラー対応**をご紹介したい(そしてActive Storage使いたい)というものです。

# 修正（2020/07/27）
伊藤さんご本人からコメントいただき、`bootsnap gem`を追加する方法に変更いたしました。
詳しくはこの記事のコメントをご確認ください🙇‍♂️

# 環境
Ruby 2.5.1
Rails 5.0.7.2

# 手順
伊藤さんのQiita記事を大いに参考にさせていただきました。
[永久保存版！？伊藤さん式・Railsアプリのアップグレード手順](https://qiita.com/jnchito/items/0ee47108972a0e302caf)

基本的には伊藤さんの記事を見ていただくのがわかりやすいです（この記事の意味）。
ただ、「とりあえず早いとこバージョン上げたい！！」という方も少なからずいらっしゃるかと思うので、邪道的な形で見ていただけると幸いです。

また、本来はテストまでカバーすべきですが、今回は**目的がActive Storageを使うこと**なので、そちらに関しては割愛します。

##1. Rails以外のgemをバージョンアップする
>Rails本体のバージョンを先に上げてしまうと、DeviseやCarrierwaveのような周辺のgemが最新のRailsに対応しておらず、思いがけないエラーが起きるかもしれません。

はい。まさに起きました。笑

###1-1. developmentとtestグループのgemを先にアップデートする
```terminal:terminal
# 該当のアプリのディレクトリで実行
$ bundle update -g development -g test
```

###1-2. トラブルが起きやすそうなgemを1つずつアップデートする
`bundle outdated`コマンドを実行すると、最新でないgemが一覧表示されます。
ただ、そこまでgemの数が多くない場合は、一気にアップデートしてしまってもいいかもしれません。

1つずつアップデートする場合は、`bundle update`の後ろにgem名を指定します。

```terminal:terminal
# deviseだけをアップデートしたい時
$ bundle update devise
```

###1-3. その他のgemをまとめてアップデートする
gem名を指定せず、`bundle update`です。
※なお、このタイミングでは**Railsのバージョンは変えないでください（元のバージョン指定のままにしておく）。Railsのバージョンアップは別途行います。**

```ruby:Gemfile
# Railsのバージョン指定は元のままにしておく
gem 'rails', '~> 5.0.7', '>= 5.0.7.2'
```

Railsのバージョン指定がされていることを確認したら、`bundle update`

```terminal:terminal
# gemをまとめてアップデートする
$ bundle update
```

##2. Railsのバージョンを上げる

GemfileでRailsのバージョン指定を変更して、`bundle update rails`です。

```ruby:Gemfile
# gem 'rails', '~> 5.0.7', '>= 5.0.7.2'
gem 'rails', '~> 5.2.4', '>= 5.2.4.2'
```

```terminal:terminal
$ bundle update rails
```

##3. rails app:updateタスクを実行する

>次にrails app:updateタスクを実行します。
このタスクを実行すると、新しいバージョンで必要になる新しいファイル作成や、既存ファイルの変更を対話形式で行うことができます。

```terminal:terminal
$ rails app:update
    conflict  config/boot.rb
Overwrite config/boot.rb? (enter "h" for help) [Ynaqdhm]
```
上記のように、コンフリクトが起きるファイルの扱いをどうするかを一つずつ確認していく作業です。
Y/n/a/q/d/hのいずれかのキーで回答します。

```
Y - Yes。上書き実行
n - No。上書きしない
a - All。このファイル以降の全ファイルを上書き
q - Quit。処理中断
d - Diff。新旧ファイルのdiffを表示
h - Help。入力する各キーの意味を表示
```

###「これ一個ずつ確認するの面倒…まとめてやっていいんじゃ？」
はい、僕もそう思って、`a` = allを実行しました。
すると`routes.rb`がまっさらに生まれ変わりました。 (白日か)

**`routes.rb`だけはしっかり確認しましょう！というより`n`にしましょう！！**

伊藤さんもこうおっしゃっています。
>僕はd = diffを確認した上で、Yかnを入力することが多いです。
（でも、routes.rb以外はほとんどYを入力しているかもしれない）

##4. 動作確認（`rails s`が起動するか）
他にもテストコードや自分の目で見て確認も必要ですが、今回は`rails s`（とりあえず開発環境でサーバー起動させる）を目指します。

###4-1. エラー①
意気揚々と`rails s`したところまずはこちらのエラーから。

`require': cannot load such file -- bootsnap/setup (LoadError)`とのエラーが。

```terminal:terminal
$ rails s
Traceback (most recent call last):
	3: from bin/rails:3:in `<main>'
	2: from bin/rails:3:in `require_relative'
	1: from /myapp/config/boot.rb:4:in `<top (required)>'
~~~config/boot.rb:4:in `require': cannot load such file -- bootsnap/setup (LoadError)
```

こちらの方法で対応できました。変更箇所は2箇所(ファイル)。

```ruby:Gemfile
# 全部の環境に適用させたいので、グループの中には入れない
gem 'bootsnap', require: false
```

```ruby:config/initializers/new_framework_defaults.rb
~
# この行↓をコメントアウト
# ActiveSupport.halt_callback_chains_on_return_false = false
~
```

###4-2. エラー②
「さあ、今度こそサーバー起動だ！」と思って`rails s`したらまたもエラーが。

```<top (required)>': undefined method `halt_callback_chains_on_return_false=' for ActiveSupport:Module (NoMethodError)```

```terminal:terminal
=> Booting Puma
=> Rails 5.2.4.3 application starting in development 
=> Run `rails server -h` for more startup options
Exiting
Traceback (most recent call last):
~~~/config/initializers/new_framework_defaults.rb:23:in `<top (required)>': undefined method `halt_callback_chains_on_return_false=' for ActiveSupport:Module (NoMethodError)
```

こちらで対応できました。

```ruby:config/initializers/new_framework_defaults.rb
~
# この行↓コメントアウト
# Rails.application.config.action_controller.raise_on_unfiltered_parameters = true
~
```

###必読の記事
今回僕が遭遇したエラーは、伊藤さんがまさにおっしゃっている部分なので、この記事は読んで理解しておくと今後に役立つと思います。
>Railsのバージョンが上がると、従来の挙動とは異なる、新しい挙動が導入される場合があります。
バージョンアップ後はすべて新しい挙動に合わせられるのが理想的ですが、場合によっては一部の挙動を古いRailsに合わせないといけないかもしれません。

>こうした挙動の変更はload_defaultsやnew_framework_defaults_x_x.rbで行います。

>load_defaultsとnew_framework_defaults_x_x.rbの関係については以下の記事で詳しく説明しているので、こちらを読んで適切に設定を変更してください。

>[config.load_defaultsとnew_framework_defaults_x_x.rbの関係を詳しく調べてみた - Qiita](https://qiita.com/jnchito/items/cce3b2795e1c66735310)

### Railsのバージョンアップは完了
これでRailsのバージョンアップは完了です。
上記手順で実行してもうまくいかない時は、サーバーの再起動（`ctrl + c`で終了、`rails s`で起動）を試してみてください。

##5. 環境変数周りのファイルってどうなるの？
環境変数を定義するファイルは、Rails5.0系では`secrets.yml`でしたが、Rails5.2系以降は`credentials.yml.enc`と`master.key`を使用するのが一般的です。

###5-0. 「あれ？credentialsもmasterキーもなくない？？」
Railsのバージョンアップをすれば勝手に作られるものだと思っていましたが、そんな美味しい話はありませんでした。
そもそも`master.key`は`rails new`時に作成されるもののはずなので、当たり前といえば当たり前ですが…


###5-1. 結論：`secrets.yml`のままで良い
特に環境変数ファイルはいじることなく動作しました。笑