こんにちは、hachi8833です。
🔗Rails: 先週の改修(Rails公式ニュースより)
- 公式更新情報: Ruby on Rails — Better error message, opt-in devcontainers and more!
- 公式更新情報: Ruby on Rails — Propshaft default for Rails 8, Guides updates, transaction.active_record events, and more!
🔗 Rails 7.2新規アプリでdevcontainerをオプトイン扱いに変更
動機/背景
このプルリクを作成した理由は、Rails 7.2でdevcontainersを今後オプトインとして扱うことが決定されたため。これにより新規アプリは、
rails new
に--devcontainer
フラグを渡した場合にのみdevcontainerセットアップを取得するようになる。さらに、既存アプリでもbin/rails devcontainer
を実行することでdevcontainerセットアップを生成可能になる。詳細
これを機能させるためのコミットを複数含んでいる。
まず、アプリケーションのジェネレータをリファクタリングして、devcontainerをオプトインできるようにした。次に、devcontainerの全ロジックをアプリケーションのジェネレータから専用のdevcontainerジェネレータに抽出した。これにより、new
コマンドとdevcontainer
コマンドの両方でロジックを共有可能になる。
devcontainer
コマンドを実行すると、アプリを起動して状態を確認し、app:update
コマンドと同じ要領でdevcontainerで必要なオプションを決定する。追加情報
従来は、devcontainer固有のロジックが
application_system_test_case.rb.tt
に置かれていた。このロジックを削除して、devcontainerジェネレータがdevcontainerを生成するときにapplication_system_test_case.rb
を更新する形にした。これにより、既存アプリでdevcontainerを生成するときにファイル全体を上書きせずに済む。
postgresql.yml.tt
にも同様にdevcontainer固有のロジックが置かれていた。今後devcontainerは、database.yml
を最新に保つために既存アプリのdatabase.yml
を更新するようになる。db:system:change
ジェネレータも修正した(修正前はdevcontainer固有の設定を含めるためにdatabase.yml
を更新していなかった)。同PRより
つっつきボイス:「Rails 7.2で採用される例のdevcontainer(ウォッチ20240228)は、当初rails new
したときにデフォルトでセットアップされるようになっていたんですが、--devcontainer
オプションをつけない限りセットアップされない方針に変わったそうです」「devcontainerのセットアップは環境によってもいろいろ変わるので、サポートはしつつデフォルトから外すことにしたんでしょうね: 不要なら.devcontainer/フォルダを削除すれば済む話なので大して影響しないかな」
参考: Developing inside a Container using Visual Studio Code Remote Development
参考: 開発コンテナーの概要 - GitHub Docs
「そういえばRails 8からはKamalがデフォルトになった(ウォッチ20240529)けど、Kamalもオプトインでいいのではという気がしますね」「言えてる😆」
「さほど使わなさそうなツールをrails new
のデフォルトにあまり増やして欲しくない気持ちはありますね: プロジェクトで使う予定がないツールでも、デフォルトでインストールされていたら新メンバーが知らずに使ってしまうみたいなことが起きる可能性があるので、devcontainerやKamalあたりはオプトイン方式の方が好み」
🔗 Kamal用のDocker Volumeが不要な場合は設定しないようになった
動機/背景
修正: #51836
このプルリクを作成した理由は、KamalのDocker永続化ストレージボリュームの設定は、SQLiteやActive Storage以外では不要と思われるため。別のデータベースと
--skip-active-storage
オプションを組み合わせる場合は、この設定をスキップ可能。詳細
このプルリクは、Active StorageをスキップしてSQLite以外のデータベースを使う場合は、永続化ストレージボリュームの設定をスキップするよう
config/deploy.yml.tt
を変更する。追加情報
自分が実装した条件は、Railsアプリジェネレータのここで使われているものと同じである。
同PRより
つっつきボイス:「Kamalのデプロイ時に利用するDocker Compose設定の生成で、Active Storageを使う場合やSQLite3を使う場合以外はDocker Volumeを利用しないようにした、なるほど」「deploy.yml.ttがKamal設定のテンプレートなんですね」「ややニッチだけどActive Storageを使わないならKamal用のDocker Volumeは不要でしょうね👍」
# railties/lib/rails/generators/app_base.rb#L369
+ def skip_storage? # :doc:
+ skip_active_storage? && !sqlite3?
+ end
...
def dockerfile_chown_directories
directories = %w(log tmp)
- directories << "storage" unless skip_active_storage? && !sqlite3?
+ directories << "storage" unless skip_storage?
directories << "db" unless skip_active_record?
directories.sort
end
🔗 RailsのプラグインジェネレータにRuboCopとGitHub Actionsを追加
- PR: Add rubocop and GitHub Actions to plugin generator by excid3 · Pull Request #51822 · rails/rails
RailsのプラグインジェネレータにRuboCopとGitHub Actionsを追加。
Chris Oliver
同Changelogより
動機/背景
RailsConf 2024の講演準備中に、Railsのプラグインジェネレーターが更新されておらず、アプリのジェネレーターに同梱されている新しいrubocopファイルとGitHub Actionsファイルがプラグインに含まれていないことに気付いた。これらは、プラグイン開発者が作業を手軽に開始するうえで特に有用。
これについて@rafaelfrancaと少し話したところ同意をもらえた。なおbrakemanの追加については「意味がない」とのこと。
動機/背景
このプルリクは、プラグインジェネレーターを更新して、GitHub Actionsとrubocopのテンプレートを含めるようにする。また、rubocopのlintにパスするようにいくつかのファイルを更新した。
これらのテンプレートは、時間の経過とともに若干変わってくる可能性があるため、アプリ テンプレートとは別にしている。
同PRより
つっつきボイス:「Rails 7.2からGitHub Actions(ウォッチ20240123)やRuboCop(ウォッチ20240117)のテンプレートを含めるようになったけど、rails plugin new
で生成するプラグインファイルにも含めるようにしたんですね」「そういえば大昔のRailsのプラグインは独自仕様だった気がするけど、もうかなり前からgemで作るようになっていましたね↓」
参考: Rails プラグイン作成入門 - Railsガイド
Railsのプラグインはgem化されています。gem形式を採用したことで、必要に応じてプラグインをRubygemsとBundlerでさまざまなRailsアプリケーションと共有することも可能です。
Rails プラグイン作成入門 - Railsガイドより
「今さらですけど、RailsプラグインはRailsエンジン↓とは別のものなんですよね?」「ガイドによればプラグインは基本的にライブラリの拡張という位置づけで、Railsエンジンは少なくともルーティングの特定のポイントにマウントして使うものだと理解しています」「なるほど」
🔗 Rails 8からPropshaftがデフォルトに
- PR: Change asset pipeline default to Propshaft in Rails 8 by dhh · Pull Request #51799 · rails/rails
Sprocketsは長年貢献してくれたが、Rails 8でPropshaftにバトンを渡すときが来た。
同PRより
つっつきボイス:「ついにRails 8からSprocketsに代わってPropshaftがアセットパイプラインのデフォルトになるのか〜😳」「もうすぐリリースされるRails 7.2をはさむことになりますね」「現行のSprocketsも今見ると最後に更新されたのが9か月前か」
🔗 Instrumentationのsql.active_record
とtransaction.active_record
に現在のトランザクションを追加
#51955の後、
sql.active_record
イベントペイロードにも現在のトランザクションオブジェクトを含めるようにした。最近追加された
ActiveRecord::Transaction#uuid
のおかげで、ユースケースとしてデータベースアクティビティのトレース(トランザクションごとにクエリをグループ化する機能など)が可能になる。
同PRより
つっつきボイス:「これはActiveSupport::Notifications
への項目追加ですね: たしかに現在のトランザクションオブジェクトへの参照を取れればいろんなことに使えるのでありがたい👍」「これは欲しい情報ですね」「なお、ActiveSupport::Notifications
はマルチスレッドで動いていないので、取り出した後の処理を増やしすぎると他のものがいろいろ詰まってしまうので注意が必要ですが、こうやって取り出せるということが大事」
# guides/source/active_support_instrumentation.md#L358
| Key | Value |
| -------------------- | ---------------------------------------- |
| `:sql` | SQL statement |
| `:name` | Name of the operation |
| `:connection` | Connection object |
+| `:transaction` | Current transaction |
| `:binds` | Bind parameters |
| `:type_casted_binds` | Typecasted bind parameters |
| `:statement_name` | SQL Statement name |
| `:async` | `true` if query is loaded asynchronously |
| `:cached` | `true` is added when cached queries used |
| `:row_count` | Number of rows returned by the query |
参考: Active Support Instrumentation で計測 - Railsガイド
参考: Rails API ActiveSupport::Notifications
「あと、以下の#51955もActiveSupport::Notifications
への項目追加ですね↓」
transaction.active_record
のサブスクライバがペイロード内のイベントに関するトランザクションを取得するのは自然だと思う。
同PRより
# guides/source/active_support_instrumentation.md#L413
| Key | Value |
| -------------------- | ---------------------------------------------------- |
| `:connection` | Connection object |
+| `:transaction` | Transaction object
| `:outcome` | `:commit`, `:rollback`, `:restart`, or `:incomplete` |
🔗 nil UUIDを定義するDigest::UUID.nil_uuid
が追加
RFC 4122は、いわゆるnil UUIDを定義している。これを
Digest::UUID
に追加して、この特殊UUIDを使えるようにしよう。
同PRより
つっつきボイス:「RFCに定義があるならそれに従う方がいい👍」「なおプルリクではRFC 4122が参照されていますが、調べてみたら4122は廃止されていて以下のRFC 9562が最新だそうです↓」
参考: RFC 9562 - Universally Unique IDentifiers (UUIDs) 日本語訳
5.9. Nil UUID
nil uuidは、128ビットすべてがゼロに設定されるように指定されている特別な形式のuuidです。
RFC 9562 - Universally Unique IDentifiers (UUIDs) 日本語訳より
🔗 schema_cache_ignored_tables?
のpublicメソッドを追加
- テーブルがスキーマキャッシュで無視されるかどうかをチェックするpublicメソッドを追加
従来は、テーブルが無視される設定になっているかどうかをチェックするために、アプリケーションでスキーマキャッシュクラスの
ignored_table?
を再実装しなければならなかった。
これをサポートするpublicメソッドが追加され、スキーマキャッシュはこれを直接利用するよう更新された。ActiveRecord.schema_cache_ignored_tables = ["developers"] ActiveRecord.schema_cache_ignored_tables?("developers") => true
Eileen M. Uchitelle
同PRより
つっつきボイス:「以前追加されたschema_cache_ignored_tables
コンフィグ(ウォッチ20210921)に加えてメソッドも追加したそうです」「あまりなさそうだけど、特定のテーブルでスキーマキャッシュを使いたくないみたいな状況が生じたときに欲しくなりそうな機能かも🤔」
参考: 週刊Railsウォッチ20210921: schema_cache_ignored_tables
設定オプションが追加
参考: 3.8.51 config.active_record.schema_cache_ignored_tables
-- Rails アプリケーションの設定項目 - Railsガイド
🔗 rails app:update
でpublic/ディレクトリも更新するよう修正
動機/背景
Railsバージョンをアップグレードするとき、
app:update
コマンドが/public
ディレクトリ内に新規ファイルを生成していない。たとえば、Rails 7.1を7.2にアップグレードしても、
406-unsupported-browser.html
ファイルが生成されない。詳細
このプルリクは、
app:update
でpublic/ディレクトリが追加されるようにする。
config_when_updating
などで行う方がよいだろうか?
同PRより
つっつきボイス:「少し前にpublic/ディレクトリに追加された"406 Not Acceptable"エラーページ(ウォッチ20240425)などがrails app:update
で追加されていなかったのを修正した、なるほど」「よくぞ気づいたという感じですね」
参考: 1.4 アップデートタスク -- Rails アップグレードガイド - Railsガイド
🔗 PermissionsPolicyにdisplay-capture
とkeyboard-map
を追加
動機/背景
display-capture
(Chrome 94)とkeyboard-map
(Chrome 97)がpolicy controller featureで標準化されたこのプルリクを作成した理由は、policy controller featureが更新されたため。
詳細
このプルリクは、
ActionDispatch::PermissionsPolicy
を更新する。
同PRより
つっつきボイス:「display-capture
とkeyboard-map
というポリシーがW3Cでサポートされるようになったのか、へ〜!」
「こういうポリシーはどう使うんでしょうか?」「サーバーがこれらの機能を使いますよという通知を正式なレスポンスとしてクライアントに返せるようになるということですね: それを受け入れるかどうかはクライアント側次第」「なるほど」「ちなみにブラウザのPermissions PolicyはCSP(Content-Security-Policy)ヘッダーとは別物ですが使い方が似ていますね: 典型的な使い方は以下の2つだと思います」
- CSPと同じく、XSSがあったときに備えて「念のため」設定しておくことで、悪用リスクを減らす。
jsbin.comのような、あえて任意コード実行を許可するタイプのWebサイトでも有用。 -
iframeで外部サイトを埋め込むときに、その外部サイトが使える権限を制限する。
参考: Permissions Policy - HTTP | MDN
参考: 8.3 Content-Security-Policy
ヘッダー -- Rails セキュリティガイド - Railsガイド
「サーバーがクライアント側のデバイスを利用するときにこうやって正規の方法で通知できれば、それ以外の方法でデバイスを使おうとする操作をクライアント側で拒否するときの判断に使えるようになると思いますし、WidgetやAnalyticsなどのような正規のものかXSSのような悪意のあるものかにかかわらず、自分たちでメンテしていないJavaScriptを動かす時にWebサイト側で制限をかけられるのは安心ですね👍」
「そういえばPermissionsPolicyはこの間のRailsセキュリティ修正でも修正が入っていましたね↓」「そうそう、ありました」
参考: Rails API ActionDispatch::PermissionsPolicy
🔗 新ドキュメント: Tuning Performance for Deployment
このガイドは、PumaとCRubyにおけるコンカレンシーやパフォーマンスの主要な原理について解説する。
(#50949のやり直し版)
同PRより
つっつきボイス:「Rails 7.2のGuidesに新しいドキュメントがマージされました」「お〜、PumaとCRubyのコンカレンシー解説が公式に入るのはありがたい🎉」「concurrent-rubyも更新されてますね」
前編は以上です。
バックナンバー(2024年度第2四半期)
- 20240514後編 Ruby/Railsのアップグレード情報をscrapboxに集約ほか
- 20240513前編 Railsコンソールが最新のIRB APIに移行、assertionless_tests_behaviorほか
- 20240426後編 Prismの歴史と現況を振り返る、Steepの"narrowing"実装の内部ドキュメントほか
- 20240425前編 RailsからOpenStructを削除、Playwrightベストプラクティスほか
- 20240423後編 Kamalはゲームチェンジャーになるか、Solid Queueで使われているfugitほか
- 20240416前編 ジョブのエンキューをトランザクション完了時まで自動先延ばしほか
- 20240410後編 SeleniumでRubyの全クラスとモジュールにRBSが追加ほか
- 20240409前編 Rails公式の"rails-new"ツールでRailsプロジェクトをセットアップほか
- 20240402 solid_queueとmission_control-jobsが正式にRailsのgemに、Rubyの"チルド"文字列ほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)