Devise 4.9をインストールしてRails 7.0 （Hotwire/Turbo）に対応する

## はじめに


Rails 7.0が2021年の暮れにリリースされて以降、Deviseは長らくRails 7.0（というか、Hotwire/Turbo）に完全対応していない状態が続いていました。ですが、ようやく2023年2月17日にRails 7.0に対応したDevise 4.9.0がリリースされました🎉

https://github.com/heartcombo/devise/releases/tag/v4.9.0

rails-ujsではなく、Hotwire/Turboを使っているRails 7.0にDeviseを組み込んでいる（もしくはこれから組み込もうとしている）人は、以下の手順に従ってDevise 4.9.0を導入してください。

:::note info
**備考**
もともとこの記事は「開発中のDeviseをインストールしてRails 7.0 （Hotwire/Turbo）のテストに協力する」というタイトルで公開していましたが、Devise 4.9.0が正式リリースされたことに伴い、タイトルと本文を修正しました。
:::

## 前提条件

- Rails 7.0を使っている
- Hotwire/Turboが有効になっている（Rails 7.0で`rails new`した場合はデフォルトで有効になっているはず）

## 手順

新規にDeviseを導入する場合はGemfileに以下の情報を追加して、`bundle install`を実行してください。

```ruby:Gemfile
gem "devise"
```

すでにDeviseを利用している場合は `bundle update devise responders` を実行して、最新版のDeviseとRespondersをインストールしてください。

インストールが終わったら、念のためDevise 4.9.0以上とResponders 3.1.0以上がインストールされていることを確認しましょう。

```
$ bundle info devise    
  * devise (4.9.0)
        Summary: Flexible authentication solution for Rails with Warden
        Homepage: https://github.com/heartcombo/devise
        Documentation: https://rubydoc.info/github/heartcombo/devise
        Source Code: https://github.com/heartcombo/devise
        Wiki: https://github.com/heartcombo/devise/wiki
        Changelog: https://github.com/heartcombo/devise/blob/main/CHANGELOG.md
        Bug Tracker: https://github.com/heartcombo/devise/issues
        Path: /Users/jnito/dev/sandbox/devise-rails-7-sandbox/vendor/bundle/ruby/3.2.0/gems/devise-4.9.0

$ bundle info responders
  * responders (3.1.0)
        Summary: A set of Rails responders to dry up your application
        Homepage: https://github.com/heartcombo/responders
        Source Code: https://github.com/heartcombo/responders
        Changelog: https://github.com/heartcombo/responders/blob/master/CHANGELOG.md
        Bug Tracker: https://github.com/heartcombo/responders/issues
        Path: /Users/jnito/dev/sandbox/devise-rails-7-sandbox/vendor/bundle/ruby/3.2.0/gems/responders-3.1.0
        Reverse Dependencies: 
                devise (4.9.0) depends on responders (>= 0)
```

### アップグレードガイドに目を通す

`bundle install`を実行すると、以下のように「Changelogやアップグレードガイドを読んでくれ」というメッセージが出力されます。

```
$ bundle install
（略）
Bundle updated!
Post-install message from devise:

[DEVISE] Please review the [changelog] and [upgrade guide] for more info on Hotwire / Turbo integration.

  [changelog] https://github.com/heartcombo/devise/blob/main/CHANGELOG.md
  [upgrade guide] https://github.com/heartcombo/devise/wiki/How-To:-Upgrade-to-Devise-4.9.0-%5BHotwire-Turbo-integration%5D
```

Changelogやアップグレードガイド（wiki）にはHotwire/Turbo対応に必要な技術情報が載っています。

僕が翻訳したアップグレードガイドの日本語訳を以下に載せておいたので、この記事を読み進める前にこちらのガイドにも目を通しておくことをお勧めします（この記事を執筆している時点ではChangelogもアップグレードガイドも内容はほぼ同じです）。

[【日本語訳】How To: Upgrade to Devise 4\.9\.0 \[Hotwire Turbo integration\]](https://gist.github.com/JunichiIto/1398835b9825a9ce3958456041f59d27)

ここから下の手順は状況によって作業が必要だったり、不要だったりします。
ご自身のアプリの状況に応じて、適切な手順を取捨選択していってください。

### `rails g devise:install`をまだ実行していない場合

`rails g devise:install` を実行します。

新規にDeviseをインストールする場合は、基本的にこれだけで対応は終わりです。ただし、ログアウト用のリンクまたはボタンの作り方だけ、この下の説明を参考にしてください。

### `rails g devise:install`をすでに実行済みの場合

`config/initializers/devise.rb`に以下の2行を追加します。

```ruby 
# ==> Hotwire/Turbo configuration
config.responder.error_status = :unprocessable_entity
config.responder.redirect_status = :see_other
```

もしくは `rails g devise:install --force` で `config/initializers/devise.rb` を再作成してください。

### ログアウトリンクを用意していた場合

`link_to`を`button_to`に変えるか、`link_to`に`data: { turbo_method: :delete }`を追加します。

```erb 
<%# rails-ujsでは動作するが、Hotwire/Turboでは動作しない %>
<%= link_to 'Sign out', destroy_user_session_path, method: :delete %>

<%# rails-ujsとHotwire/Turboの両方で動作する %>
<%= link_to 'Sign out', destroy_user_session_path, method: :delete, data: { turbo_method: :delete } %>
<%= button_to 'Sign out', destroy_user_session_path, method: :delete %>
```

### 独自のviewでアカウント削除ボタンを用意していた場合

ボタンに`data: { turbo_confirm: "Are you sure?" }`を追加します。

```diff_erb 
-Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
+Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
```

ボタンではなくリンクにしたい場合は以下のコードを利用します。

```erb
<%# rails-ujsとHotwire/Turboの両方で動作する %>
Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?", turbo_method: :delete }, method: :delete %>
```

### 独自のviewでOmniAuthを使ってログインリンクを用意していた場合

`link_to`を`button_to`に変え、Turboを無効化します。Turboを無効化するのはCORSエラーの発生を防止するためです。

```diff_erb 
-<%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br />
+<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
```

### devise-i18nを使っていた場合

devise-i18nはバージョン1.11.0でDevise 4.9.0に対応しています。

https://github.com/tigrish/devise-i18n/blob/master/CHANGELOG.md#1110

devise-i18nを使っている場合は`bundle update devise-i18n`でバージョンを1.11.0以上に上げてください。

また、viewをカスタマイズしている場合は、上で説明した内容を手作業で反映するか、`rails g devise:i18n:views`でviewを再生成してください。

### すでにTurboを動かすためにあれこれ変更していた場合

Deviseで特に凝ったことをやる必要がなければ、上記の対応でDeviseがTurboに対応するはずです。

ただし、ネットの情報を参考にしてすでにDeviseのTurbo対応を進めていた場合は、その対応を元に戻す必要があります。

以下に僕が以前書いた記事を例に挙げて、元に戻す内容を記述します。

https://qiita.com/jnchito/items/5c41a7031404c313da1f

上記の記事を読んでTurbo対応していた場合は、修正点を元に戻すため、以下の対応を実施してください。

- Deviseのformに付けていた`data: { turbo: false }`を外す（Turboを有効化する）
- RegistrationsControllerとSessionsControllerを削除する
- `config/routes.rb`のcontrollersオプションを無くす

```diff_ruby:config/routes.rb
-devise_for :users, controllers: { registrations: 'registrations', sessions: 'sessions' }
+devise_for :users
```

https://qiita.com/jnchito/items/48db78c465493837c41f

上記の記事を読んでTurbo対応していた場合は、修正点を元に戻すため、以下の対応を実施してください。

- TurboDeviseControllerを削除する
- `config/initializers/devise.rb`内のTurboFailureAppを削除する
- `config/initializers/devise.rb`内の`parent_controller`、`navigational_formats`、`warden`の設定をそれぞれコメントアウトする

## まとめ

手順は以上です。これで心置きなくRails 7.0に移行できますね！！🎉