Rails7+deviseで起こり得るエラーとその対処法

## はじめに
Railsを使ったことがある人なら1度はお世話になるgem 'devise'

本稿執筆時点(2022/03/14)でdevise(Ver4.8.1)はまだRails7に完全対応してません
>4.8.1 - 2021-12-16
>enhancements
>Add support for Rails 7.0. Please note that Turbo integration is not fully supported by Devise yet.

[deviseの更新履歴][devise]

実際に導入した時に、いろいろ調べたところ日本語で書かれているのが少なかったので
Rails7でもdevise使いたいよ!!!! という人の一助になればと、まとめてみました。
素人に毛が生えたような人間が書いてるので、おかしなところなどは指摘していただけるとありがたいです。


## 開発環境
Ruby 3.1.1
Rails 7.0.2.3
devise 4.8.1

## 発生する可能性のあるエラー
- サインアップ時に以下のエラーが出る
```
NoMethodError (undefined method `user_url' for #<Devise::RegistrationsController....>
```
- サインアウト時に、リンクを押してもURLが変になり無反応

- サインアウトできてるが、ターミナル上で以下のエラーが出ている
```
ActionController::RoutingError (No route matches [DELETE] "/"):
```
- フラッシュメッセージが出ない


## 対処法
こちらの[ディスカッション][discussion]がすごく役に立ちました！！

- devise.rbの修正
　まず、以下のコードを冒頭に追加し、途中のコードのコメントアウトを外してコードを修正します。
```ruby:config/initializer/devise.rb
class TurboFailureApp < Devise::FailureApp
  def respond
    if request_format = :turbo_stream
      redirect
    else
      super
    end
  end

  def slip_format?
    %w(html turbo_steam */*).include? request_format.to_s
  end
end
# frozen_string_literal: true
'中略'
-  # config.parent_controller = 'DeviseController'
+  config.parent_controller = 'TurboDeviseController'
'中略'
-  # config.navigational_formats = ['*/*', :html]
+  config.navigational_formats = ['*/*', :html, :turbo_stream]
'中略'
-  # config.warden do |manager|
+  config.warden do |manager|
+    manager.failure_app = TurboFailureApp
  #   manager.intercept_401 = false
  #   manager.default_strategies(scope: :user).unshift :some_external_strategy
-  # end
+  end
'以下省略'
```
TurboDeviseControllerについては2項で説明します。

- TurboDeviseControllerの作成
　app/controllersの中に、TurboDeviseControllerを作成します。
```ruby:app/controllers/turbo_devise_controller.rb
class TurboDeviseController < ApplicationController
  class Responder < ActionController::Responder
    def to_turbo_steam
      controller.render(options.merge(formats: :html))
    rescue ActionView::MissingTemplate => error
      if get?
        raise error
      elsif has_errors? && default_action
        render rendering_options.merge(formats: :html, status: :unprocessable_entity)
      else
        redirect_to navigation_lcation
      end
    end
  end

  self.responder = Responder
  respond_to :html, :turbo_steam
  
end
```
以上2点を行うことで、deviseでのサインアップ、サインイン、サインアウトが可能となりました。
deviseでのフラッシュメッセージが出ないエラーに関しても、上記対処法で解決するかと思います。


```
ActionController::RoutingError (No route matches [DELETE] "/"):
```
このエラーに関しては、ログを見返すまで気づきませんでした。
(画面上はrootに設定したページに戻っていた為)
サインアウトのリンクを[こちらの記事][記事]を参考に
```ruby
- <%= link_to "サインアウト", destroy_user_session_path, data: { turbo_method: :delete } %>
+ <%= button_to( "サインアウト", destroy_user_session_path, method: :delete ) %>
```
にしたところ、エラーは消えました。

## 最後に
これからいろいろ使っていく中で、他のエラーにも遭遇するかもしれません。
そのときは、また記事にしようかなぁと思っています。

駄文にお付き合いいただき、ありがとうございました。

## 参考文献

https://gorails.com/episodes/devise-hotwire-turbo

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

https://github.com/heartcombo/devise/issues/5446

https://betterprogramming.pub/devise-auth-setup-in-rails-7-44240aaed4be



[devise]:https://github.com/heartcombo/devise/blob/main/CHANGELOG.md
[discussion]:https://gorails.com/episodes/devise-hotwire-turbo
[記事]:https://betterprogramming.pub/devise-auth-setup-in-rails-7-44240aaed4be