Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JunichiIto/1398835b9825a9ce3958456041f59d27 to your computer and use it in GitHub Desktop.
Save JunichiIto/1398835b9825a9ce3958456041f59d27 to your computer and use it in GitHub Desktop.
【日本語訳】How To: Upgrade to Devise 4.9.0 [Hotwire Turbo integration]

How To: Upgrade to Devise 4.9.0 [Hotwire Turbo integration] · heartcombo/devise Wiki の日本語訳です。

ところどころ意訳していますが、明らかに間違った訳があればコメント欄で教えてください。

日本語版の最終更新日: 2023-02-17

How To: Devise 4.9.0へのアップグレード(Hotwire/Turbo対応)

Changelogを確認してください

https://github.com/heartcombo/devise/blob/main/CHANGELOG.md

Hotwire / Turbo

本バージョンのDeviseはHotwire / Turbo / Turbo-Railsの各フレームワークに対応しました。

Changelogでは利用開始に必要な大半の情報を記述していますが、このwikiでもひとつずつ変更点を説明していきます。

最新の Responders (v3.1.0 以上) を使う

フォーム送信に関するTurboのドキュメントを引用します。

フォーム送信によってステートフルなリクエストが送られると、Turbo DriveはサーバがHTTP 303リダイレクトのレスポンスを返すことを期待します。これにより、リロードすることなくページを更新し、画面遷移を実現します。

このルールの例外は4xxまたは5xxのステータスコードでレスポンスがレンダリングされた場合です。この例外があることで、サーバが422 Unprocessable Entityを返したときはバリデーションエラーがレンダリングされ、サーバが壊れていて500 Internal Server Errorだった場合は"Something Went Wrong"が表示されます。

Devise(とResponders)はこれまでバリデーションエラーが発生したときは200 OKを返し、リダイレクトでは302 Foundを返していました。これはどちらもレンダリングとリダイレクトのRailsのデフォルトの挙動でした。Hotwire/Turboの登場により、Railsは新しい要件に合わせて422 Unprocessable Entityでレンダリングしたり、303 See OtherでGETしないリダイレクトを実現したりするように変わりました。

Hotwire/Turboに対応し、上記の新しいデフォルト挙動に合わせるため、Deviseは最新バージョンのResponders(v3.1.0以上)を利用しなければなりません。これを使うと、バリデーションエラー発生時のエラーレスポンス(error_status)と、POST/PUT/PATCH/DELETEリクエスト後のリダイレクトレスポンス(redirect_status)を自由に設定できるようになります。

新規に作成したアプリでは、rails generated devise:installを実行すると最初からこの新しい設定が導入されます。既存のアプリをアップグレードする場合は、以下の設定を追加することで新しいレスポンスの挙動を採用することができます。

# config/initializers/devise.rb
Devise.setup do |config|
  # ...
  config.responder.error_status = :unprocessable_entity
  config.responder.redirect_status = :see_other
  # ...
end

後方互換性のため、Deviseの内部ではerror_status:ok (200 OK)に、redirect_status:found(302 Found)に設定されています。上記の設定を追加することで、エラーとリダイレクトのステータスが422 Unprocessable Entity303 See Otherに設定されます。これにより、Hotwire/Turboの要件に適合できます。

最新のDeviseと、この設定をサポートしない古いバージョンのRespondersを組み合わせた状態で上記の設定を追加すると、警告が表示され、Deviseの挙動に変化は起きません。

注意:将来的にはRails + Hotwire/Turboのデフォルトに合わせて、Deviseのデフォルトも変更される可能性があります。

独自のresponderを確認する

もしあなたが独自のresponderをアプリケーションに設定し、Deviseにもその挙動を反映させたい場合は、Deviseがそのresponderを利用するためにconfig.responder = MyApplicationResponderのようにしてDeviseのresponderをまるっと置き換える必要があるかもしれません。

Deviseで独自のresponderを使う主な理由は、前述のとおりステータスを変更できるようにするためです。しかし、やろうと思えば独自のresponderの設定を変更することもできます。そうすればDeviseはその設定を使います。詳しくはRespondersのREADMEを参照してください。

重要:もしあなたがHotwire/Turboに対応するためだけに独自のresponderとfailure appの両方、もしくはどちらか一方を作ってレスポンスを変更していたなら、もうそのresponderとfailure appは必要ありません。

:turbo_streamはナビゲーション可能なフォーマット

Turbo Railsは:turbo_stream MIME フォーマットからのリクエストを識別できるように、そのフォーマットを登録しています。新しいDeviseはこのフォーマットをナビゲーション可能なフォーマット(navigational format)として認識します。これにより、Turboを使用する場合、このフォーマットがHTMLナビゲーションのように動作します。

注意:もしあなたがこれまで:turbo_streamをナビゲーションしないフォーマット(non-navigational format)として扱っていた場合は、config/initializers/devise.rb内のnavigational_formatsを変更することで、このフォーマットをナビゲーション可能なフォーマットから除外することができます。

リンクとボタンに関する挙動の変更

以下の情報はDeviseが提供するデフォルトの shared views/links (コピーしてから変更してないもの) を使っており、なおかつ(もしくは)rails-ujsからTurboに移行する場合に関係する話題です。

shared viewsにあるOmniAuthのサインインリンクがボタンに変わった

OmniAuthの"Sign in with"リンクはこれまでmethod: :postを使っていました。これはPOSTリクエストをサーバに送信し、それからプロバイダ(訳注:OAuthプロバイダ)へリダイレクトするためです。この動作にはrails-ujsが必須でした。この仕組みは(data: { turbo_method: :post }のようにして)Turboで動かそうとしても動作しません。なぜならPOST fetchリクエストのあとでリダイレクトしようとするとCORSエラーが発生するからです。

デフォルトでHotwire/Turboとrails-ujsの両方で互換性を保つようにするため、shared views内のリンクは(button_toヘルパーを使って)ボタンに変更されました。これにより、method=POSTとなるHTMLフォームが生成されます。新しいRailsアプリではrails-ujsはデフォルトで利用できなくなっていますが(訳注:Rails 7以降ではrails-ujsではなくHotwire/Turboがデフォルトで組み込まれる)、ボタンであればHotwire/Turboとrails-ujsの両方で動作します。

この変更はOmniAuthが有効かつ、Deviseが提供するデフォルトのdevise/shared/_links.html.erbパーシャルを使っているアプリにのみ適用されます。大半のアプリはおそらくこのパーシャルをコピーして変更していると思われます。その場合はこの変更が適用されません。ですが、もしあなたがアプリ内でshared viewsのリンクを直接使っている場合、ボタンのスタイルを変更するか、(rails-ujsを使っているなら)viewをコピーしてボタンをリンクに戻すか、どちらかの作業が必要になるかもしれません。

data-confirmdata-turbo-confirm

data-confirmオプション(ボタンやフォームをサブミットする前に表示する確認モーダルに追加するオプション)は、Turboで動作するようにdata-turbo-confirmに変更する必要があります(rails-ujsは変更不要です)。Deviseでは後方互換性を維持するため、アカウント削除用の"Cancel my account"ボタンに両方のオプションを追加しています。

<%# rails-ujsでは動作するがTurboでは動作しない %>
<%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
<%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>

<%# Turboでは動作するがrails-ujsでは動作しない %>
<%= button_to "Cancel my account", registration_path(resource_name), data: { turbo_confirm: "Are you sure?" }, method: :delete %>
<%= link_to "Cancel my account", registration_path(resource_name), data: { turbo_confirm: "Are you sure?", turbo_method: :delete } %>

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

Deviseはshared linksでbutton_toを採用しています。これはTurboとrails-ujsの互換性を簡単かつ適切に提供できるためです。このviewをあなたのアプリにコピーする場合は、rails-ujsまたはTurboのどちらかに合わせて適切なコードを選択してください。

注意: ボタンにdata: { turbo_confirm: "<message>" }を付ける場合はturbo-rails v1.3.0以上を使う必要があります。これより前のバージョンであれば、form: { data: { turbo_confirm: "<message>" } }を使ってボタンを囲むフォームにこのオプションが付くようにしてください。(この変更点はTurbo 7.2.0に含まれています。このバージョンではこちらの修正によって挙動が変更されています。)

data-methoddata-turbo-method

data-methodオプション(リンクからサブミットする際のリクエストメソッドを設定するオプション)はdata-turbo-methodに変更する必要があります。button_toformであればTurboが適切に処理してくれるのでこの変更は必要ありませんが、rails-ujsでサブミットするリンクはTurbo用の修正が必要になります。

もしあなたが:delete(これはデフォルトです)でログアウトするようにDeviseをセットアップし、method: :deleteオプションを使って(フォームで囲まれたボタンではなく)ログアウト用のリンクを使っている場合は、修正が必要になります。(Deviseはログアウト用のリンクやボタンをshared viewsで提供していません。)

<%# rails-ujsでは動作するがTurboでは動作しない %>
<%= link_to "Sign out", destroy_user_session_path, method: :delete %>

<%# Turboで動作する %>
<%= button_to "Sign out", destroy_user_session_path, method: :delete %>
<%= link_to "Sign out", destroy_user_session_path, data: { turbo_method: :delete } %>

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

もしリンクを使っている場合は、あなたのアプリが適切なオプションを選択していることを確認するか、幅広い互換性(訳注:Turboでもrails-ujsでも使えるようにすること)を考えてフォームに囲まれたボタンを使うように実装を変更してください。


アップグレード中に何か問題が発生したら報告してください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment