6の新しいデフォルト設定と安全な移行方法を詳しく解説(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社エンジニアの「?」を「!」に。原著者の許諾を得て翻訳・公開いたします。app:updateで生成されるnew_framework_defaults_6_0.rbの9つのデフォルトフラグについてひととおり解説します。6.0と堂々と書けるようになります。5.2のデフォルト設定を使っているアプリを前提としています。5.2と書かれているかどうかを調べることで確認できます。簡単のため、以下のデフォルト設定ではRails.application.config.を省略しています。falseフラグの機能formのaccept-charset属性は、IE5やその時代のブラウザで導入されました。この属性は、送信するform要素のデータで用いるエンコーディングをブラウザに指定します。Railsはやがてaccept-charset="UTF-8"を自動的に追加してUTF-8での送信をブラウザに強制するようになりました。5には困った振る舞いがいくつかありました。5のデフォルトcharsetで表現できる場合は、accept-charsetを無視するのです。Latin-1はフランス語やドイツ語などのヨーロッパ系言語で用いられていました)。5からフォームを送信したとき、入力をすべてLatin-1で表現できてしまう場合、accept-charset属性は無視され、Latin-1でエンコードされたフォームが送信されます。formフィールドに追加されました。5にaccept-charset属性を守らせます。このsnowmanはその後、ログに雪だるまの絵文字が出力されるのを嫌がる人たちがいることからチェックマーク「✓」に変更されました。Qiitaこのチェックマーク記号は未だにRailsフォームのhiddenフィールドに居座っています。このフラグのコメントを外すと、チェックマーク記号はフォームに含まれなくなります。これらのブラウザをサポートしなくてもよければ、コメントを外しても安全です。trueフラグの機能Railsはcookie値を暗号化および署名し、cookie値の暗号化を解除して署名を照合することで、悪者によって改変されていないことを確認します。この方法では、一部のcookieで暗号化済みおよび署名済みの値を悪者がコピーして、他のcookieの値として用いることまでは防げません。次のシナリオで考えてみましょう。アホ)2つのcookieの暗号化/署名済みの値を悪者が入れ替えるRailsはリクエストに含まれる値を読み取って「よろしい、値は改変されていない」と承認するRailsはユーザーを「adminかつdoofusでない」と認識するが、実際は「非adminかつdoofus」フラグの話に戻ります。このフラグをコメント解除すると、「purpose」というフィールドをcookieに埋め込んでから、暗号化と署名を行うようになります。するとRailsは、上のステップ3で「ふむ、値はどちらも改変されてはいないが、cookieの名前とpurposeが一致しておらぬな」と判断します。して悪人は相変わらずdoofusのままです。このフラグを安全に有効にするにはこのフラグをコメント解除しても既存のcookieが壊れることはありません。cookieはリクエスト時に読み込まれ、レスポンスではpurposeフィールドを追加してリライトされます。以後、新しいcookieにはpurposeフィールドが含まれるようになります。このオプションは従来のRailsと互換性がありません。アプリ全体の移行が終わって6.0で安定運用してから有効にするのがベストです。恐ろしげなwarningが表示されますが怖がることはありません。6.xにロックインされますよと言っているのです。5.xへのダウングレードは不可能になります。6で安定運用できることを確認できれば、このフラグは安全にコメント解除できます。falseフラグの機能HTTPレスポンスにはcontent-typeが含まれています。text/htmlのように設定されます。このヘッダーには”text/html”というメディアタイプだけが含まれていることにご注目ください。このフラグをコメント解除すると、このヘッダーに他の値も追加されるようになります。charset=utf-8のようにcharsetが含まれます。このヘッダーの値は、以前からActionDispatch::Response#content_typeで調べられるようになっていますが、この値にもcharsetが含まれるようになります。このフラグを安全に有効にするにはこのフラグをコメント解除すると、外部と内部の両方に影響が生じます。外部向けとしては、アプリのユーザーがレスポンスで完全なcontent-typeヘッダーを受け取るようになります。ユーザーがcontent-typeをあれこれ調べるようなことがなければ、これといった問題はないと考えても大丈夫です。内部では、ActionDispatch::Response#content_typeの値が従来とは異なるものになります。影響が生じるかどうかはテストスイートでわかるでしょう。specが使われているかもしれません。(required)>'修正の指針としては以下が考えられます。Jobにはbefore_enqueueなどのライフサイクルコールバックがあることを、きっと皆さまもご存知でしょう。MyJob.perform_later(true)job1は、フラグの設定にかかわらず、キューに入ったジョブクラスのインスタンスになります。現時点ではjob2も同様です。このフラグをコメント解除すると、コールバック内でabortがスローされてjob2はfalseになります。このフラグを安全に有効にするにはコードベースでabortをgrepしてください。abortのインスタンスを調べて、ジョブのコールバックにabortが出現しないようにしましょう。ジョブのコールバックでabortを見つけてしまったら、ジョブがどこでキューに入ったかを調べる必要があります。常にジョブインスタンスにするために、その箇所がperform_laterに依存しないようにします。運悪くperform_laterに依存していたら、falseでもやっていけるようにリファクタリングする必要があります。Storageでファイルがアタッチされると、ActiveStorage::Attachmentのafter_commit_createコールバックが呼び出されます。このコールバックによってActiveStorage::AnalysisJobがキューに入ります。実行されると、このジョブでActiveStorage::Blob#analyzeが呼び出されます。このメソッドは、ファイルからメタデータを抽出するのにプラグインシステムを用いています。このメタデータは、blobレコードのmetadataカラムに保存されます。これは、mini_magickを使って画像からheightやwidthを取り出すときによく使われます。現在のActiveStorage::AnalysisJobはdefaultキューに入ります。このフラグをコメント解除すると、専用のactive_storage_analysisキューに送信されるようになります。これによって、ジョブのカスタム優先順位レベルをアプリで設定できるようになります。このフラグを安全に有効にするにはこのフラグをコメント解除すると、新しいActiveStorage::AnalysisJobはactive_storage_analysisキューに入るようになります。キューのバックエンドがこのキューのジョブを処理できるように設定されていることを確認する必要があります。Sidekiqを使うアプリの場合、active_storage_analysisキューをconfig/sidekiq.ymlに追加する必要があります。ここに記載した順序によって、他のキューとの相対的な優先順位が決定されます。キューに入った既存のジョブが壊れることはありません。従来どおりdefaultキューで処理されます。以下のコードがあるとします。User.create.avatar.attach(some_image_file)sam.avatar.attach(different_image_file)最初のファイルがアタッチされると、S3などのストレージにアップロードされ、Railsはそのストレージの場所を指すレコードを1件作成します。2番目のファイルがアタッチされると同様にS3にアップロードされますが、Railsはこのレコードを更新して、新しいストレージの場所を指すように変更します。Storageはファイルをほったらかしにはしません。ActiveStorage::PurgeJobがキューに入り、最終的にファイルをS3から頑張って削除します。現在のActiveStorage::PurgeJobはdefaultキューに入ります。このフラグをコメント解除すると、以後は専用のactive_storage_purgeキューに送信されます。これによって、ジョブのカスタム優先順位レベルをアプリで設定できるようになります。このフラグを安全に有効にするにはこのフラグをコメント解除すると、新しいActiveStorage::PurgeJobはactive_storage_purgeキューに入るようになります。キューのバックエンドがこのキューのジョブを処理できるように設定されていることを確認する必要があります。Sidekiqを使うアプリの場合、active_storage_purgeキューをconfig/sidekiq.ymlに追加する必要があります。ここに記載した順序によって、他のキューとの相対的な優先順位が決定されます。キューに入った既存のジョブが壊れることはありません。従来どおりdefaultキューで処理されます。以下のコードがあるとします。StorageはファイルをS3などのストレージにアップロードします。ここで最終行の配列uploadsに再代入したらどうなるでしょう?Railsは既存の配列と新しい配列の差を取る。新しいファイルをアップロードすると、配列に既に存在するファイルは無視される。Railsは配列の差分を取らない。既存のファイルをすべて破棄して新しい配列内のファイルをすべてアップロードする。現在のRailsの挙動は1.です。コメント解除するとRailsの挙動は2.になります。このフラグを安全に有効にするにはコードベースでhas_many_attachedをgrepします。これによって変更の影響を受けるモデルを特定できます。モデルが影響を受けないのであれば、このフラグを安全にコメント解除できます。モデルが影響を受ける場合は、再代入を行っている箇所をリファクタリングしてattachを使うことをおすすめします。attachは、既存のファイルに触らずに、渡されたファイルを素朴にアタッチします。ファイルの重複防止がアプリで重要な場合は、ファイル重複防止ロジックを自分で追加する必要があります。"ActionMailer::MailDeliveryJob"フラグの機能ActionMailer::DeliveryJobは、Railsメイラーでdeliver_laterが呼ばれたときにキューに入るジョブです。changeを入れることを望みました。これではRailsのアップグレード中に既存のジョブが壊れるかもしれません。そこで新たにActionMailer::MailDeliveryJobを作ることが決まりました。このフラグをコメント解除すると、以後新しいActionMailer::MailDeliveryJobクラスによるメイラージョブがキューに入るようになります。狙いは、新しいActionMailer::MailDeliveryJobがキューに入ってもActionMailer::DeliveryJobが引き続き処理されるようにすることです。ActionMailer::DeliveryJobのジョブは今後キューに入らなくなるので、このクラスは最終的に不要になります。6.1で削除する予定です。6.1で削除されます。この設定は以前のRailsとの後方互換性がありません。メールをバックグラウンドで送信すると、ジョブワーカーはMailDeliveryJobですべてのデリバリージョブが正しく送信されるようにする必要があります。アプリの移行が完全に終わって6.0で安定運用するようになってから、この設定を使いましょう。恐ろしげなwarningが表示されますが怖がることはありません。6.xにロックインされますよと言っているのです。5.xへのダウングレードは不可能になります。6で安定運用できることを確認できれば、このフラグは安全にコメント解除できます。5.2でリサイクル可能なキャッシュキーが導入されました。Recordのcache_keyのうち変動の可能性があるupdated_atがcache_versionに移動します。5.2でキャッシュキーが変化しなくなっているのがわかります。5.2ではキーを再利用してキャッシュエントリを更新するようになりました。これによってキャッシュミスが減少し、パフォーマンスが向上します。このフラグをコメント解除すると、リサイクル可能なキャッシュキーがActiveRecord::Relationなどのコレクションにも導入されます。"users/query-b03a3611aaa3ed0825f6b93870f69c0e"このフラグを安全に有効にするにはこのフラグは安全にコメント解除できます。私は以下の2つの理由から、さほどややこしくならずに済むだろうと思うことにしています。第1に、この変更が懸念材料となるのは、ユーザーのコードではなくキャッシュアダプタ(Redisなど)の側です。この機能をサポートしないモダンなアダプタはちょっと思いつきません。keys」)があることです。6.0を有効にする第10のフラグです。これはnew_framework_defaultsには含まれていません。このフラグは、RailsのオートローダーをclassicからZeitwerkに切り替えます。:zeitwerkを呼べます。オートローディング)。実際にはつらい点は1つしか見当たりません。Zeitwerkはイニシャライザ内でのオートロードをサポートしなくなりました。テストを実行するときに以下のようなwarningが出力されていないかどうか探してみましょう。初期化時に定数Fooがオートロードされました。この挙動を有効にする機能は非推奨であり、初期化時のオートロードは今後のバージョンのRailsでエラーになります。再読み込みしてもアプリは再起動しないので、コードは初期化中に再実行されません。したがってFooを再読み込みしても、期待する変更は古いClassオブジェクトに反映されなくなります。オートロードされたこれらの定数はアンロードされました。何が問題か以下の2つのファイルがあるとします。FooclassicモードのRailsは、イニシャライザで上のコードがある場合にFooを問題なくオートロードします。BAZ.bar?は期待どおりtrueを返します。foo.rbを編集してfalseを返すようにしたらどうなるでしょうか。BAZ.bar?はtrueを返します。理由は、コードが再読み込みされてもイニシャライザは再実行されないからです。Fooの値はアプリケーションを再起動するまでそのままになります。Zeitwerkでは、そのような自分の足を撃ち抜く銃を使えません。初期化中にオートロードを検出すると、定数をアンロードしてwarningを表示します。解決法そのオートローディングを削除することです。Fooが1つのイニシャライザだけで参照されているのであれば、定義をそのイニシャライザに移動するだけで済みます。Foo複数箇所から参照されているのであれば、オートロードされない場所(libなど)にfoo.rbを移動し、明示的にrequireします。Foowarningが消えてテストがgreenになれば、Zeitwekを安心して使えるようになります。コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。enno.jpを運営。実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。Storageを使ってはいけない(翻訳)#Tags#会社紹介#自社サービス#勉強会#Rails#PHP#デザイン#実績#週刊RailsウオッチCONTACTお気軽にご相談ください。(翻訳)CONTACTTechRachoでは、パートナーシップをご検討いただける方からのご連絡をお待ちしております。お気軽にご意見・ご相談ください。