こんにちは、hachi8833です。
えっRubyKaigiまであと一ヶ月(切ってる)!?!?!?!?!?!?!?
— Misaki Shioi (しおい) (@coe401_) March 17, 2025
🔗Rails: 先週の改修(Rails公式ニュースより)
- 公式更新情報: Ruby on Rails — Rails World CFP, YJIT configuration and more!
- 公式更新情報: Ruby on Rails — Ignoring indexes in MySQL has never been so easy...
🔗 bundler-auditのコンフィグがデフォルトで追加された
アプリケーションのGemfileに既知のセキュリティ問題があるかどうかの探索はすべてのCIフローに組み込むべき。
同PRより
つっつきボイス:「DHH自らのプルリクです」「お、bundler-auditがデフォルトで追加されたのか」「これがbinstubですね↓」「bundler-auditはgemのセキュリティチェックの定番として継続的にCIとかで動かすものだし、コードを直接書き換えるものでもないので追加しておいていいと思う👍」
# railties/lib/rails/generators/rails/app/templates/bin/bundler-audit.tt
require_relative "../config/boot"
require "bundler/audit/cli"
ARGV.concat %w[ --config config/bundler-audit.yaml ] if ARGV.empty? || ARGV.include?("check")
Bundler::Audit::CLI.start
🔗 RuboCopがRuby 2.7より新しいRuby構文をチェックできるようになった→取り消し
RuboCopの対象となるRubyバージョンが、デフォルトの2.7から利用中のRubyバージョンに変更された。
Jeremy Daer
同Changelogより
つっつきボイス:「そうそう、RuboCopにはTargetRubyVersion
でRubyバージョンを指定できるけど、そのバージョンを環境変数などから拾うようになったんですね」
# railties/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt
# Omakase Ruby styling for Rails
inherit_gem: { rubocop-rails-omakase: rubocop.yml }
+AllCops:
+ TargetRubyVersion: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || RUBY_ENGINE_VERSION %>
「あれ、直後にcad2196でこのプルリクが取り消されてる」「#54692のコメントを見ると、Rubyバージョンをチェックするコードは前からあったけど、それに気づかずに作ったプルリクがマージされてしまったので後から取り消したのね: こういうこともありそう」
RuboCopはデフォルトで現在のRubyバージョンを使うが、特定の状況(親ディレクトリの
.ruby-version
に依存するプラグイン内のtest/dummy
アプリなど)ではバージョンを推測できない。コミットcad2196より
🔗 bundleのbinstubを生成しないようになった
Railsの新規アプリケーション作成で
bin/bundle
というbinstubを生成しなくなった。
bin/bundle
binstubは、適切なバージョンのbundlerを有効にするために使割れていたが、このメカニズムはRubygem自体に組み込まれたため不要になった。Edouard Chin
同Changelogより
動機/背景
- 修正:
AuthenticationGeneratorTest#test_authentication_generator_without_bcrypt_in_gemfile
fails with ruby 3.5.0dev at 8-0-stable branch · Issue #54563 · rails/railsBundlerが新しいリリースをカットしたときに、
rails new
が警告を発したり、bin/rails g authentication
がクラッシュしたりしないようにするため。詳細
Bundlerは今後のバージョンで、
bundle binstub bundler
を実行してもbin/bundle
binstubを生成しないようになった。Bundler側でこの変更が行われた理由は、rubygems/rubygems#8345に詳しい。問題
Bundlerの変更がリリースに組み込まれると、新しいRailsアプリケーションを生成したときにBundlerが警告を発して、
bin/bundle
を使うAuthenticationGeneratorが動かなくなる。解決方法
Bundlerのbinstubの生成を停止し、ジェネレーターを変更してコードベースの残りの部分と同じBundlerコマンドを使うようになった。
同PRより
つっつきボイス:「お、bundlerのbinstabが新しいbundlerで動かなくなったという問題なのね: 現在はそもそもRubygemsでbundlerのbinstubを生成しなくなったし、bundlerのバージョンが適切に選ばれるようにRubygemが改善されたので、bundlerのbinstubを生成しないことになったという流れなのか」「binstubはRailsのbin/
ディレクトリに置かれる実行ファイルのラッパースクリプトでしたね↓」
このプルリクの元になったエンドユーザーや開発者の問題
Bundlerが生成したbinstubが厳しすぎて、直接エラーが発生してBundlerの自動インストールと自動切り替えメカニズムがトリガーされないことがあった。
適切なバージョンのBundlerを有効にするためのメカニズムは2つあるが、1つを除けばほとんど同じ。
- 1: RubyGemsで行う場合。
これにより、最も適切なBundlerバージョンがリストの先頭に配置されるが、存在しない場合は他のバージョンにフォールバックする。
このメカニズムはBundlerのコードでもバックアップされており、ロックされたバージョンのBundlerを自動的にインストールし、最初に最適なバージョンが有効になっていない場合にそのバージョンでBundlerを再起動する。- 2: Bundler binstubsで行う場合。
これは実際にはBundlerのバージョンに~> x.y
制約を設定するため、エラーが発生する可能性がある。特に、
vendor/bundle/
が設定済みで、ロックされたバージョンのBundlerと一致するマイナーバージョンのBundlerが実行されている場合、Bundlerのbinstubsはエラーで終了する。Bundlerのbinstubsが配置されていなければ、Bundlerの内部メカニズムはvendor/bundle/
以下にあるBundler自体のロックされたバージョンで自動的に再起動し、すべて正常に動作する。このプルリクで実装されている問題の修正方法
サポートしているすべてのRubyGemsバージョンに同じ(かつ厳しくない)メカニズムが存在するため、Bundler自体のbinstubは不要になった。このため、binstubの生成を停止することにした。
rubygems/rubygems#8345より
🔗 before_validation
やafter_validation
にexcept_on
オプションが追加された
- PR: Add
except_on:
option for validation callbacks by bensheldon · Pull Request #54665 · rails/rails
動機/背景
このプルリクは、
before_validation
コールバックとafter_validation
コールバックにexcept_on:
オプションを追加する。詳細
before_validation
コールバックとafter_validation
コールバックは、on: :create
やon: :update
の他に、on: :some_custom_value
などのカスタムバリデーションのコンテキストをサポートする唯一のコールバックである。
except_on:
オプションは、既に#43495でvalidates
などのバリデーションに追加された。
このプルリクは、before_validation
コールバックとafter_validation
コールバックにも同じオプションを追加することで、オプションを一貫させる(ところでexcept_on:
は本当に素晴らしい!@DRBraggに感謝😅)
同PRより
つっつきボイス:「お、今まではどんな場合にバリデーションするかをバリデーションコンテキストのon:
オプションで指定できたけど、このexcept_on:
オプションでも指定できるようになったんですね: これはよさそう👍」「言われてみればon:
が使えるなら逆の条件も指定できる方がいいですね」
# activemodel/test/cases/validations/callbacks_test.rb#L64
before_validation :set_before_validation_marker_on_context_b, on: :context_b
+ before_validation :set_before_validation_marker_except_on_context_a, except_on: :context_a
after_validation :set_after_validation_marker_on_context_a, on: :context_a
after_validation :set_after_validation_marker_on_context_b, on: :context_b
+ after_validation :set_after_validation_marker_except_on_context_a, except_on: :context_a
🔗 YJITを有効にするときにハッシュ形式でオプションを渡せるようになった
動機/背景
現在のRailsでは
config.yjit = true
でYJITを有効にできるが、この設定ではYJITオプションの設定まではサポートされていなかった。
RUBYOPT="--yjit-log"
を設定することで統計やログなどのオプションを有効にできるが、これらのオプションをconfig.yjit
経由で直接構成する方法が提供されていない。YJIT自体 では、
RubyVM::YJIT.enable(stats: false, log: false)
という方法でこれらのオプションを有効にできるので、Railsの設定レイヤ内で管理する方が便利。詳細
このプルリクは、
config.yjit
を拡張してハッシュを受け取れるようにし、ユーザーがYJITオプションを指定可能にする。config.yjit = true # デフォルト設定でYJITを有効にする config.yjit = { stats: true } # YJITをカスタムオプションで有効にする(新しくサポート) config.yjit = false # YJIT を無効にする
同PRより
つっつきボイス:「細かな改良だけど、ハッシュ形式でオプションを渡せるようにすることで、YJITをオン/オフすることに加えて今後オプションを増やすことも可能になりますね👍」
🔗 CSPのnonceをサードパーティのビューにも設定可能になった
動機/背景
コンテンツセキュリティポリシー(CSP)のコンテキストで
nonce
を利用する場合、現在のビューで使われるタグにnonce
属性を自動的に追加できない。つまり、
nonce
属性は、それを必要とする各タグ(javascript_tag
、javascript_include_tag
、stylesheet_link_tag
)に手動で追加しなければならない。自分の理解では、現時点ではこれらの
nonce
をタグに自動的に追加する方法は存在しない。
- 自分が特定した現状のソリューションは以下のとおり。
javascript_include_tag
およびstylesheet_link_tag
ヘルパーをオーバーライドして、nonce
属性を明示的に追加する。- 各タグに手動で
nonce: true
を追加する。この場合、サードパーティから直接取得したビュー内のタグには反映されないため、アプリケーションがそれらを信頼しているにもかかわらず、CSPによってブロックされる可能性が生じることになる。必要なタグで
nonce
属性を自動的に有効にする設定オプションを利用可能にするのが理想的。もっとよい方法があるかどうか、およびそうしない方がよい理由があるかどうかについては、自分にはわからない。
詳細
このプルリクの主な変更は、
content_security_policy_nonce_auto
設定オプションの追加である。
これにより、content_security_policy_nonce_directives
設定オプションで指定されたディレクティブの影響を受けるタグにnonce
が自動で含まれるようになる。現在の振る舞いを維持するために、新しい設定オプションはデフォルトでfalse
に設定される。追加情報
これにより、開発者は各タグに手動で追加することなく、必要なタグの
nonce
属性を手軽に有効にできる。また、ビューがサードパーティgemの内部にある場合でも、アプリケーションによって信頼され使われているgemは自動的にnonce
属性の恩恵を受けられるようになる。繰り返すが、もっとよい方法があるかどうか、およびそうしない方がよい理由があるかどうかについては、自分にはわからない。
このプルリクエストを改善する方法についてのフィードバックや提案を求む。
同PRより
つっつきボイス:「これは、content_security_policy_nonce_auto
というコンフィグを追加して、これが有効な場合はサードパーティgemのビューも含めてCSP(コンテンツセキュリティポリシー)のnonce
属性を自動でJSやCSSのタグに設定してくれるようになった: 自動でやってくれるのはありがたい👍」
参考: nonce
- HTML: ハイパーテキストマークアップ言語 | MDN
参考: §9.3.2 nonce
を追加する -- Rails セキュリティガイド - Railsガイド
🔗 スキーマ形式をデータベース単位で指定可能になった
動機/背景
このプルリクによって、マルチデータベースのアプリケーションで、データベースごとに
schema_format
を個別に設定可能になる。個人的には、レガシーアプリケーションを変換してRails標準の手法に1つずつ移行するときに、この機能が必要だと感じた。また、(特定の機能を使うために)データベースを
structure.sql
に切り替える必要があるが、すべてのデータベースでそうする必要がない場合にも有用。詳細
データベース設定ファイルで
schema_format
にruby
またはsql
を設定可能になった。この項目が存在しない場合は振る舞いは変更されず、アプリケーション全体の設定が使われる。または、適切な環境変数が存在する場合はその環境変数が使われる。
同PRより
つっつきボイス:「Railsのデータベーススキーマは標準のRuby形式の他にSQL形式も選べますけど、データベースごとに指定する方法が意外にもなかったんですね」「これまで必要に迫られたことがなかったけど、特に古い外部データベースでスキーマ形式をSQLにしたくなることはありそうなので、確かにスキーマ形式はデータベースごとにも指定可能にすべきですね👍」
データベース設定ファイルで
schema_format
を設定できるようになった。primary: schema_format: ruby
マルチデータベースのセットアップでデータベースごとにフォーマットを変えたい場合に有用。
T S Vallender
同Changelogより
参考: § 6.2 スキーマダンプの種類 -- Active Record マイグレーション - Railsガイド
🔗 RailsガイドにdevcontainerでPodmanを使う方法を追加
つっつきボイス:「これはRailsガイドの更新です」「devcontainerでPodmanを使えるようにする機能自体は既に追加されているのね↓」
「Podmanを知らなかったので調べてみたところ、Dockerとは別のコンテナシステムなんですね」「そうそう、PodmanはRed Hatがかなり昔からやっているDockerのオルタナ的なソフトウェアで、Dockerと同じくOCIというコンテナ標準規格にも沿っているはず↓」「Podmanはroot権限がなくても動かせるのが売りだけど、その後Dockerも似たようなことができるようになったみたいですね」
参考: オープン・コンテナ・イニシアティブ(OCI)仕様の謎解き | Docker
参考: Podman使ってみた & Dockerとの違いは? #Docker - Qiita
参考: Podman とは?をわかりやすく解説
Podman が他のコンテナエンジンと異なるのは、デーモンを使用しないという点です。つまり、コンテナを実行するのに、root 権限を持つプロセスを必要としません。
「RailsでPodmanを使いたい人ってどのぐらいいるんでしょう?」「Red Hat Enterprise Linux(RHEL)で動かしているプロジェクトだとRed Hadが公式にサポートするソフトウェアを使うことになってPodmanが必要になるとかはありそうですね」「なるほど」
参考: Red Hat Enterprise Linux operating system
なおDockerコンテナのビルドの高速化も行われたそうです↓。
🔗 SQLiteアダプタにActiveRecord::Result
のcolumn_types
を追加
- PR: Add column types to
ActiveRecord::Result
for SQLite3 by ankane · Pull Request #54594 · rails/rails
これにより、
ActiveRecord::Result#cast_values
でPostgreSQLの場合と同様に、SQLiteで日付や時刻をキャスト可能になる。これは、ActiveRecord::Base.lease_connection.select_all
を利用するクエリで有効。カラム型は、PostgreSQLの場合と同様にカラム名または位置で参照可能。関連するPostgreSQLアダプタコード: rails/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb at v8.0.1 · rails/rails
同PRより
つっつきボイス:「PostgreSQLで使えていたActiveRecord::Result
のcolumn_types
をSQLiteでも使えるようにしたそうです」「このあたりを見ると、従来はSQLiteの場合はEMPTY_HASH
にされてたんでしょうね↓」「なるほど」「SQLiteアダプタの改修だけど、PostgreSQLアダプタも少し変更されてるのが面白い」
# activerecord/lib/active_record/result.rb#L102
def initialize(columns, rows, column_types = nil)
# We freeze the strings to prevent them getting duped when
# used as keys in ActiveRecord::Base's @attributes hash
@columns = columns.each(&:-@).freeze
@rows = rows
@hash_rows = nil
- @column_types = column_types || EMPTY_HASH
+ @column_types = column_types.freeze
+ @types_hash = nil
@column_indexes = nil
end
参考: Rails API ActiveRecord::Result
🔗 RailsのルーティングをGTGで最適化
- PR: Speed up GTG Simulator by reducing slices/matches by skipkayhil · Pull Request #54491 · rails/rails
RailsフレームワークのJourneyで使われているGTG(Generalized Transition Graph)は、ルーティング処理を高速化するために使用される技術。GTGは以下の特徴を持つ。
- 非決定性有限オートマトン(NFA)を用いてルート定義を表現する。
ルート定義をトークンに分解し、抽象構文木(AST)を構築した後、NFAに変換する。
状態遷移表を使用して、URLのマッチングを効率的に行います。
複数のルート定義を単一のNFAで表現することができ、ORノードを使用して結合します。
文字列による遷移(string_states)と正規表現による遷移(regexp_states)を組み合わせて、柔軟なルーティングを実現します。
JourneyでGTGを使うことで、大規模なアプリケーションでのルーティング処理を高速化し、効率的なURLマッチングを実現する。
Perplexity の Eliot より: pplx.ai/share
つっつきボイス:「こちらはルーティングの最適化です」「GTGの詳細はわからないけど、状態遷移図があることからもルーティングのツリーを高速化する技術ですね↓」
参考: Generalized transition graph (GTG) definition with Example | Engineer's Portal
🔗Rails
🔗 Rails World 2025のCFP募集(Rails公式ニュースより)
Start drafting your talks: the #RailsWorld CFP is now live! The CFP will remain open until April 10th, and we will inform all applicants before ticket sales launch in April or early May. Good luck to all applicants! https://t.co/v9eaMnZFtF pic.twitter.com/l1OesW77oG
— Ruby on Rails (@rails) March 7, 2025
つっつきボイス:「今年のRails World 2025は9月にアムステルダムで開催だそうです」「4/10とあるのはRails WorldのCFPの締め切りなんですね」
🔗Ruby
🔗 RubyKaigi 2025とZJIT
Maybe we'll see αJIT next.
— Yukihiro Matz (@yukihiro_matz) March 9, 2025
つっつきボイス:「今回のRubyKaigi 2025は型の話題が多いようです」「今度はZJITが登場か: 今のところRubyKaigi 2025のプロポーザル以上の情報がなさそうだけど」「発表者がYJITと同じMaxime Chevalierですけど、もしかしてYの次だからZなんでしょうか?」「MatzもZの次はαかもってツイートに書いてる😆」
今回は以上です。
バックナンバー(2025年度第1四半期)
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)