こんにちは、hachi8833です。RubyKaigi 2025お疲れさまでした。以下のscrapboxまとめがものすごい量になっていますね。
来年は函館ですね。
来年のRubyKaigiの会場情報が更新された。函館アリーナと市民会館のW使いだった!すごい。
たしかにアリーナ単体だと複数セッションがちょっとしんどいので、2つ使うのは大正解な気がする。楽しみ。https://t.co/hzmjZwxsDN https://t.co/Qo099IYEpg— 941 / kushii (@941) April 22, 2025
🔗Rails: 最近の改修(Rails公式ニュースより)
- Ruby on Rails — Ignoring indexes in MySQL has never been so easy...
- Ruby on Rails — Capturing error reports in tests and more
- Ruby on Rails — must-understand, with_default_isolation_level, Rails World CFP and more!
🔗 インデックス作成/変更でMySQLのINVISIBLE
やMaria DBのIGNORED
を指定可能になった
動機/背景
このプルリクの目的は、MySQL v8.0.0以降の
(ALTER/CREATE) INDEX ... INVISIBLE
とMariaDB v10.6.0以降の(ALTER/CREATE) INDEX .... IGNORED
機能のサポートをRailsに統合し、Rails環境内でのインデックス管理機能を強化すること。インデックスを非表示にすると、インデックスのメンテナンスや更新は引き続き可能になるが、クエリオプティマイザでの利用が許可されなくなる。この機能により、インデックスの変更をより段階的に展開できるため、インデックスの利用や削除が確定される前に開発者がパフォーマンスへの影響を監視できるようになる。詳しくは以下を参照。
現在、このマイグレーションはSQL文として実行可能である。ただし、この制限により、
schema.rb
ファイルへの反映が不十分となり、schema:load
プロセス中にインデックスの表示/非表示の状態が正確に取得されない。インデックスの表示/非表示を、既存のカラムメソッドやインデックスメソッドを介して変更できる機能を追加することで、
schema.rb
内でインデックスのインデックスの表示/非表示状態が適切に表現されるようになる。この機能強化により、インデックスの表示/非表示が明確になるだけでなく、これらのオプションの管理も容易になり、必要に応じてインデックスの表示/非表示の変更を容易に実装・取り消し可能になる。詳細
このプルリクは、インデックス作成時にINVISIBLE/IGNOREDを有効・無効にするサポートをActive Recordのマイグレーションに追加する。
add_index :users, :email, enabled: false enable_index :users, :email add_column :users, :dob, :string, index: { enabled: false } change_table :users do |t| t.index :name, enabled: false t.index :dob t.disable_index :dob t.column :username, :string, index: { enabled: false } t.references :account, index: { enabled: false } end create_table :users do |t| t.string :name, index: { enabled: false } t.string :email t.index :email, enabled: false end
インデックスオプションが拡張され、
enabled: true/false
オプションを認識するようになった。このオプションを使うことで、既存のカラムメソッドやインデックスメソッドでインデックスを非表示として作成可能になる。既存のインデックスの表示/非表示を管理するための
enable_index
メソッドとdisable_index
メソッドも2つ追加された。どちらのマイグレーションも取り消し可能である。この機能はMySQL v8.0.0以降とMariaDB v10.6.0以降でのみサポートされており、それに応じてArgument/Not Implementedエラーが発生する。
SQLiteには対応する機能が存在しない。
PostgreSQLにはindisvalid
フラグがあり、これがtrue
の場合、インデックスは維持されるがクエリプランナーで使えなくなる(「INVISIBLE/IGNORED」インデックスと同様)。
ただしこのフラグは、インデックスが破損していると見なされた場合に PostgreSQLによって自動的に更新されることもあり、必要に応じて更新するにはスーパーユーザー権限が必要。これは、クエリプランナーでのユーザー管理インデックスの扱いとはあまり似ていないため、このプルリクではこの機能を PostgreSQLには拡張しないことにした。近い将来この機能をPostgreSQLのインデックスのenable/disable
機能に追加することについて以下で議論している。参考: Thread: Proposal to Enable/Disable Index using ALTER INDEX : Postgres Professional
このオプションを
enabled: true/false
と命名した理由は、クエリでインデックスが使われているかどうかをより明確にするため(他の候補にはvisible: true/false
やignored: true/false
もあった)。
ALTER INDEX
は、MySQLとMariaDBの両方でインデックスの「表示/無視」の状態を変更するために使われている。しかし、ALTER INDEX
はPostgreSQLでも他のインデックス操作に使われているため、alter_index
メソッドをクエリでのインデックス利用と結びつけたくなかった。そこで、代わりにクエリにおけるインデックス利用を「有効化/無効化」する専用のメソッドを作成した。
同PRより
つっつきボイス:「MySQLだとINVISIBLE
でMariaDBだとIGNORED
、PostgreSQLだとindisvalid
で、SQLiteにはないんですね」「インデックスのINVISIBLE/IGNORED機能は以前調べたことあったかも: 大規模アプリの細かいDBチューニングで使いたいことはありそうですが、通常の規模のRailsアプリではそこまで積極的に使うことはなさそうですね」「なるほど」
🔗 ErrorReporterAssertions
にcapture_error_reports
が追加
ActiveSupport::Testing::ErrorReporterAssertions#capture_error_reports
を導入指定のエラークラスに一致するブロック内から報告されるすべてのエラーをキャプチャする。
reports = capture_error_reports(IOError) do Rails.error.report(IOError.new("Oops")) Rails.error.report(IOError.new("Oh no")) Rails.error.report(StandardError.new) end assert_equal 2, reports.size assert_equal "Oops", reports.first.error.message assert_equal "Oh no", reports.last.error.message
Andrew Novoselac
同Changelogより
つっつきボイス:「capture_error_reports
ブロックで囲まれたエラーはキャプチャされるけど、止まらずに実行を継続するようですね」「これはテストで便利なんでしょうか?」「キャプチャするけどraiseしないみたいなテストコードは一般にはあまり書かないかな...と思ったけど、よく見ると、これは割と最近(Rails 7.0)入ったErrorReporter
の一部なので、あくまでエラーレポートのための機能なのか」「あ、そっちでしたか!」「上のコードで生成しているエラーオブジェクトはエラーレポート用なので、raiseするかどうかとは関係ないヤツですね: エラーレポートならこの機能が欲しくなるのもわかる👍」
参考: Rails アプリケーションのエラー通知 - Railsガイド
参考: Rails API ActiveSupport::Testing::ErrorReporterAssertions
🔗 GitHub Actionsワークフローで実行済みのRuboCopをキャッシュする機能を追加
GitHub ActionsワークフローテンプレートのRuboCopジョブにRuboCopキャッシュ復元機能を追加。
Lovro Bikić
同Changelogより
このプルリクを#54703 (コメント) (cc @byroot、 @Earlopain)のフォローアップとしてオープンする。
GitHub ActionsアプリとプラグインのワークフローテンプレートのRuboCopジョブに、RuboCopキャッシュの復元機能を追加する。目的は、実行するワークフロー同士で可能な限りキャッシュを共有することでRuboCopチェックを高速化すること。この高速化は、コードベースが大きくなるにつれてはっきり現れる (個人的な例: 自分が作業しているコードベースでは、キャッシュなしでRuboCopの違反をスキャンするのに8分かかるが、以後のキャッシュあり実行では約40秒で済む)。
この実装の理由は、こちらに詳しい(後世のためのWaybackリンク)。
重要なポイントを以下にまとめる。
- このキャッシュは、「GitHub ActionsランナーのOS」「Rubyバージョン」「コードベース内の任意の
.rubocop.yml
ファイル」「Gemfile.lock
」のいずれかが変更されると無効化される。これは、ランナーOSの変更時にキャッシュを無効化するためのRuboCopのキャッシュの有効性ルールとキャッシュアクションのプラクティスに厳密に沿っている。デフォルトブランチ(master/main)では、ワークフローを実行するたびに新しいキャッシュエントリが作成される。これにより、RuboCopキャッシュが最新の状態になる。このように実装した理由は、GitHub Actionsキャッシュはイミュータブル(不変)であり、それを「更新」する唯一の方法は新しいエントリを作成することとなっているため。
デフォルト以外のブランチでは、このキャッシュはベースブランチから復元され(利用可能な場合)、RuboCopの実行終了後に新しいエントリとしてそのブランチに保存される。これらのブランチには単一のキャッシュが存在する(無効化が発生しない場合: 最初の箇条書きを参照)。
これらのブランチで単一のキャッシュを使うことを選択したのは、キャッシュストレージの使用量増加と、以後のコミットで多数のソースファイルが変更された場合にRuboCopのチェック速度が若干低下する(これらのファイルに対するRuboCopのキャッシュが無効化され、新しいキャッシュが作成されるため)こととのトレードオフの結果である。
デフォルトブランチでは、コミットごとに新しいキャッシュエントリを作成して最新の状態に保つ必要があるが、それ以外のブランチですべてのコミットをキャッシュするのは費用対効果が低いと思われる(特にコミット間で大きな変更がない場合)。GitHub Actionsの古いキャッシュエントリは、7日間以上利用されない場合は削除される。
ユーザーは、キャッシュエントリを削除するためのカスタムワークフローを作成してキャッシュをより早い段階で削除することも可能。
同PRより
つっつきボイス:「GHAって何だろうと思ったらGitHub Actionsでした」「RuboCopの実行結果のキャッシュをtmp/rubocopに保存しているんですね: コードベースが大きくなればなるほどRuboCopの実行は重くなるので、GitHub ActionsでRuboCopの実行結果をキャッシュできるならぜひ使いたい👍」「CIで時間を節約できる機能はありがたいです🙏」
# railties/lib/rails/generators/rails/app/templates/github/ci.yml.tt#L48
<%- unless skip_rubocop? -%>
lint:
runs-on: ubuntu-latest
+ env:
+ RUBOCOP_CACHE_ROOT: tmp/rubocop
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
+ - name: Prepare RuboCop cache
+ uses: actions/cache@v4
+ env:
+ DEPENDENCIES_HASH: ${{ hashFiles('.ruby-version', '**/.rubocop.yml', 'Gemfile.lock') }}
+ with:
+ path: ${{ env.RUBOCOP_CACHE_ROOT }}
+ key: rubocop-${{ runner.os }}-${{ env.DEPENDENCIES_HASH }}-${{ github.ref_name == github.event.repository.default_branch && github.run_id || 'default' }}
+ restore-keys: |
+ rubocop-${{ runner.os }}-${{ env.DEPENDENCIES_HASH }}-
- name: Lint code for consistent style
run: bin/rubocop -f github
「ちなみにGitHub Actionsは無料枠だとこうしたキャッシュなどの容量が割と小さいので、自分で消さないと容量不足になったりしがち」「必要なら課金しないとですね」
🔗 PostgreSQLとSQLiteでOUTER JOIN
の結果をupdate_all
するときにself-joinするようになった
PostgreSQLとSQLiteの
UPDATE
は、OUTER JOIN
がON
句内の更新済みテーブルを参照する場合、クエリを中断せずにJOIN条件をWHERE
句に移動できない。そのため、現在の実装ではサブクエリを使うしかない。これは、より積極的な操作で対応できる。更新済みテーブルを主キーのself-join(自己結合)でFROM
句に複製する。UPDATE "products" SET ... LEFT JOIN "categories" ON "products"."category_id" = "categories"."id" ... 他のjoin ... WHERE ...
つまり、上は以下に変換される。
UPDATE "products" AS "alias" SET ... FROM "products" LEFT JOIN "categories" ON "products"."category_id" = "categories"."id" ... 他のjoin ... WHERE "alias"."id" = "products"."id" AND ...
この変換により、
"products"."?"
が参照するテーブルが変更される。最上位のFULL|RIGHT OUTER JOIN
は、LEFT|INNER JOIN
に変換される。
更新コンテキストを考慮すれば、これは問題ないはず。PostgreSQLでは、サブクエリと同様に、クエリプランにインデックススキャンステップが追加される。
残念ながら、この方法では曖昧さが生じる可能性がある。
SET
またはWHERE
が対象テーブルの未修飾カラムを参照している場合、候補となるテーブルが2つ存在するため、曖昧さが生じる。これはActive Recordで生成するノードでは発生しないはずだが、手動でノードを作成するユーザーに影響する。
同PRより
つっつきボイス:「追加されたテストコード↓を見ると、left_outer_joins
とwhere
で受け取ったActiveRecord::Relation
オブジェクトに対してupdate_all
を実行できるようにしたということのようですね」「なるほど」「プルリクにも書かれているように、OUTER JOIN
を使うとテーブル名が一意でなくなったりするんですよね: やりたいことはわかったけど、個人的にはこういう怖そうな書き方よりも、従来のようにidリストをpluck
などで取り出してからサブクエリでやる方がいいかも」
# activerecord/test/cases/relation/update_all_test.rb#174
def test_update_all_with_left_outer_joins_can_reference_joined_table
pets = Pet.left_outer_joins(:toys).where(toys: { name: ["Bone", nil] })
assert_equal true, pets.exists?
assert_equal pets.count, pets.update_all(name: Arel.sql("COALESCE(toys.name, 'Toyless')"))
assert_equal "Toyless", Pet.where.missing(:toys).first.name
assert_not_equal "Toyless", Pet.joins(:toys).first.name
end
🔗 ブラウザキャッシュ制御用のmust-understand
ディレクティブを追加
RFC 9111に基づいて
must-understand
ディレクティブを実装。この
must-understand
ディレクティブは、キャッシュがレスポンスのステータスコードのセマンティクスを理解しなければならないこと、理解できない場合はレスポンスを破棄するよう指示する。このディレクティブは、キャッシュの適切な動作を保証するために、必ずno-store
と併用する必要がある。class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) if @article.special_format? must_understand render status: 203 # Non-Authoritative Information else fresh_when @article end end end
heka1024
同Changelogより
つっつきボイス:「must-understand
はHTTPの新し目のヘッダーに関連していそう: 名前から挙動が想像しにくいけど、RFC 9111をざっと見た限りでは、HTTPクライアント(ブラウザなど)がステータスコードに応じたキャッシュ要件を正しく理解できない場合はキャッシュするなと指示するためのディレクティブらしいので、いずれにしろキャッシュ制御関連の機能ですね」「また知らないヘッダーが登場した...」
must-understand
レスポンスディレクティブは、レスポンスのキャッシュを、そのレスポンスのステータスコードの要件を理解し、それに準拠するキャッシュのみに制限する。
must-understand
ディレクティブを含むレスポンスには、no-store
ディレクティブも含めるべき(SHOULD)。
must-understand
ディレクティブを実装したキャッシュが、このディレクティブを含むレスポンスを受信した場合、キャッシュがステータスコードのキャッシュ要件を理解し、実装している限り、no-store
ディレクティブを無視すべき(SHOULD)。
RFC 9111 - HTTP Cachingより
参考: must-understand
-- Cache-Control - HTTP | MDN
Cache-Control: must-understand, no-store
参考: Cache-Control: must-understand ディレクティブとは何か | blog.jxck.io
🔗 Active Recordにwith_default_isolation_level
が追加
- PR: [ActiveRecord] Introduce with_default_isolation_level by kirs · Pull Request #54836 · rails/rails
大規模なアプリケーションのデータベースを新しいデータベース分離レベルに移行する場合、アプリ内の領域ごと(またはベースコントローラごと)にデフォルトの分離レベルを適用することを検討することになる。
新しいレベルとブロックを受け取る
#with_default_isolation_level
のようなメソッドがあれば、このような移行作業が大幅に軽減されることが見込まれる。例:
class ApiV2Controller < ApplicationController around_action :set_isolation_level def set_isolation_level Product.with_default_isolation_level(:read_committed) do yield end end end # ApiV2Controllerのサブクラスであるすべてのコントローラで新しい分離レベルを強制的に取得させる
マルチデータベースアプリで適切に動作させるため、デフォルト値をスレッド/Fiber変数ではなく、コネクションオブジェクトに保存することを選んだ。
同PRより
つっつきボイス:「データベースの分離レベルというと...」「データベースのトランザクション分離レベルは、とてもよく使われる概念ですね: 以下はPostgreSQLの場合↓ですが、設定方法や実際の細かい振る舞い(phantom readなどの対応マトリクス)についてはRDBMSごとに違っています」「そうでした、READ COMMITTED
とかREAD UNCOMMITTED
みたいな指定のことですね」
参考: SET TRANSACTION
-- PostgreSQL 16.4文書
-- https://www.postgresql.jp/document/16/html/sql-set-transaction.htmlより
SET TRANSACTION transaction_mode [, ...]
SET TRANSACTION SNAPSHOT snapshot_id
SET SESSION CHARACTERISTICS AS TRANSACTION transaction_mode [, ...]
--ここでtransaction_modeは以下のいずれかです。
ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
READ WRITE | READ ONLY
[ NOT ] DEFERRABLE
「トランザクション分離レベルは要件に応じてセッション単位で変えたりすることがありますが、このプルリクはトランザクション分離レベルを#with_default_isolation_level
で明示的にブロックレベルで指定できるようにしたということですね」「なるほど」「マルチデータベースでも動くように、この設定をコネクションオブジェクトに保存しているのもごもっとも」
🔗 SessionsController#destroy
テンプレートのリダイレクトステータスを302から303に修正
動機/背景
Rails 8.0で導入された新しい認証ジェネレーターで生成されるSessionsControllerは、
destroy
アクションで302リダイレクトレスポンスを返す。これは、リダイレクト先に同じHTTP verbを適用するか、GETリクエストに変更するかがブラウザ任せになってしまうため、避けるべき。関連するHTML仕様はここに記載されている。
この問題はRails APIドキュメントでも言及されており、いわゆる「二重削除」の潜在的な原因として挙げられている。テストの結果、多くの最新ブラウザはHTTP verbを
GET
に変更することが確認されているが、この振る舞いは変更される可能性があるため、HTTP仕様を尊重するのが正しい判断だと思われる。詳細
修正されるissue: #54848(自分がオープンした)
このプルリクは、ジェネレーターが生成する
SessionsController#destroy
アクションテンプレート内のリダイレクトステータスコードを302から303に変更する。追加情報
実験ベースでは、以下のブラウザがHTTP verbを
GET
に変更することが示されている。
- Firefox 136.0.4
- Chrome 134.0.6998.89
- Safari 18.3.1
同PRより
つっつきボイス:「destroy
アクションのリダイレクト後ステータスは303(see other)が基本だけど、SessionsControllerを生成したときのステータスコードがテンプレートで指定漏れで302(Found)になっていたんですね」「修正はわずか1箇所だけでした↓」
# railties/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt#L17
def destroy
terminate_session
- redirect_to new_session_path
+ redirect_to new_session_path, status: :see_other
end
end
「RFC 9110↓によると、ステータス302の場合はブラウザがPOSTのリダイレクトをGETに変更しない可能性もあるのがよろしくないんでしょうね」「変更してもいいということはしなくてもいいということか...」「ステータス303によるPOSTのリダイレクトは必ずGETに変更されるので望ましいということですね」
注: 歴史的な理由で、ユーザーエージェントは後続のリクエストでリクエストメソッドをPOSTからGETに変更してもよい(MAY)。この振る舞いが望ましくない場合は、代わりにステータスコード307(Temporary Redirect)を利用可能。
302 Found
-- RFC 9110: HTTP Semanticsより
参考: 302 Found - HTTP | MDN
参考: 303 See Other - HTTP | MDN
「ブラウザがPOSTのリダイレクトをPOSTのままにすることは普通ないと思いますし、現実のメジャーなブラウザも302リダイレクトでPOSTをGETに変換してくれてはいるようですが、仕様で確定していないブラウザの振る舞いを当てにするよりは、仕様に沿った振る舞いになるステータスコードを使う方がよいでしょうね👍」
🔗 Cache#read_counter
とCache#write_counter
が追加
- PR: Add
Cache#read_counter
andCache#write_counter
by ghiculescu · Pull Request #54855 · rails/rails
Cache#read_counter
とCache#write_counter
を追加Rails.cache.write_counter("foo", 1) Rails.cache.read_counter("foo") # => 1 Rails.cache.increment("foo") Rails.cache.read_counter("foo") # => 2
Alex Ghiculescu
同Changelogより
関連: #54821 (comment)
このプルリクは、
Rails.cache
に2つの新しいメソッドread_counter
とwrite_counter
を導入する。これらのメソッドの目的は、
increment
/decrement
されている値を直接読み書きすること。これは、カウンタのread
/write
呼び出しでraw: true
を渡さなければならないというコードの臭いを回避するため(これは一部のキャッシュ実装でのみ必要)。
同PRより
つっつきボイス:「これはカウンタキャッシュをread_counter
とwrite_counter
で即値(immediate value)を手軽に読み書きできるようにしたということですね」「ここで言うコードの臭いとは何でしょうか?」「read
やwrite
で即値を読み書きするときに毎回raw: true
を指定しないといけないのがあまりよくないということだと思います」「なるほど、いちいちraw: true
を指定しなくてもread_counter
とwrite_counter
だけで読み書きできるようにしたということなんですね」
🔗Rails
🔗 未完成の機能を隠す(Ruby Weeklyより)
つっつきボイス:「フィーチャーフラグの話かなと思ったら、もっとシンプルな記事でした」「環境変数で動作モードをチェックしてyield
するだけという素朴な方式ですね: 環境に依存するコードをアプリケーションに書くのはあまりいいことではないけど、環境の代わりにコンフィグから読み込むようにすれば改善できますね」「なるほど」
# 同記事より
# app/helpers/application_helper.rb
module ApplicationHelper
def under_construction
if Rails.env.development?
yield
end
end
end
🔗 RubyUI: PhlexベースのUIコンポーネント集(Ruby Weeklyより)
つっつきボイス:「ViewComponentのライバルでphlex-railsというPhlexをベースにしたコンポーネントがありますけど、それをベースにした無料のUIコンポーネント集で、ビルドが高速なのが売りのようです」「現代だとこういうフロントエンドをどこまでRailsでやるかというのはありますが、UIコンポーネントは一通り揃っているようですし、使ってみたい人にはいいかも👍」
RubyUIより
「ViewComponentは、Railsだけで完結させるなら十分ありだと思うんですが、現代のフロントエンドと実装方法がまったく異なるのもあってか今ひとつ盛り上がっていない」「ViewComponent、筋はいいと思うんですけどね」
🔗 rubyevents.org: Ruby関連の直近・今後のイベントを一望できるサイト(Ruby Weeklyより)
- 元記事: rubyevents.org
つっつきボイス:「この間取り上げたFindyさんのテックカンファレンス情報の海外版といった趣です」「Ruby関連のイベント情報を集約したサイトですね: トーク別、登壇者別、開催日別のビューもあって便利そう👍」
「Balkan Ruby 2025って本当にバルカン半島(ブルガリア)で開催されるんですね」「RubyKaigi 2025はまだ個別のトークが登録されてないけど、これからかな」「ここでコントリビュート募集していますね」
rubyevents.orgは、どうやらRubyVideo.devがリニューアルしたようです↓。
Bye bye 👋🏻 https://t.co/tQxacjbx9M
Say hello to https://t.co/92k9SQ1xte 🚀 https://t.co/GY5ImIyyLs
— Adrien Poly (@adrienpoly) April 3, 2025
🔗 その他Rails
We received over 2,200 applications for this opening, but we're still reviewing everyone by hand and by human. No AI screening here. It's a lot of work, but well worth doing to find the best candidate of the lot. https://t.co/f8wbrkzCKS
— DHH (@dhh) April 24, 2025
つっつきボイス:「Railsの作者DHHがいる37signalsがジュニア開発者を募集したら2,200人も応募があったそうです」「この人数の応募者をAIを使わずに人力でチェックするのは大変そう」
🔗Ruby
🔗 Ruby 3.5.0 preview1リリース(Ruby公式ニュースより)
つっつきボイス:「RubyKaigi 2025の会期中に3.5.0 preview1がリリースされていました」「以下は言語内部の小さな変更ですね: *nil
でnil.to_a
を呼ばないようにすることで配列がアロケーションされないようにするとともに、**nil
でnil.to_hash
を呼ばない振る舞いと一貫させるようにした」
「Unicodeのバージョンも15.1.0に上がるんですね🎉」「RubyKaigi 2025のオープニングキーノートでima1zumiさんが話していたヤツですね↓」
🔗 ZJIT
つっつきボイス:「RubyKaigi 2025でShopifyのMaximaさんが発表した新しいJITであるZJITが、これも会期中にマージされました」「YJITに続けて新たにZJITを投入するという決定がすごい」「しかもYJITの開発も停止することになったそうです(バグ修正は継続)」「なるほど、YJITは当面使われ続けることになりそうですね」
🔗JavaScript
🔗 書籍『JavaScript for Rails Developers』
つっつきボイス:「翻訳記事でもお馴染みのRails Designerが最近出した書籍で、Hotwireを使い倒せばここまでやれるという感じの内容のようです」「書籍のプレビューをざっと見た限りでは、Stimulusの内部にも言及しているようですね: 特にStimulusはこういう体系的な解説があまり出回ってなさそうなので、そのあたりをまとめて読めるのはよさそう👍」「ボリュームディスカウントもやっていますね(5人で$169)」
なお、同サイトにはこんなキャッチコピーがありました↓。
Finally, JavaScript explained while keeping my Ruby soul intact.
https://javascriptforrails.com/より
🔗言語/ツール/OS/CPU
🔗 wrkflw: GitHub Actionsをローカルでバリデーション・実行できるRust製ツール
GitHub Actions workflowのvalidationとローカル実行ができるツール。Rust実装。いいね。少なくともvalidationとしてpre-commitに入れておきたい。ローカル実行はDocker上も手元も可能。brew install wrkflwだ。 / “GitHub - bahdotsh/wrkflw: Validate and execute GitHub…” https://t.co/5toEeLbnP6
— matsuu (@matsuu) April 23, 2025
つっつきボイス:「この間も話題に出たactも類似のツールだけど割と使いにくいので(ウォッチ20250409)、wrkflwでうまくやれるんだったら嬉しい👍」「READMEにあるTUIって何だろうと思ったらText User Interfaceのことみたいです↓」「昔からncursesなどでやっていたようなテキストベースのUIのことですね」
なお、取り急ぎ自分のMacbook環境で手元のRails 8アプリを試してみたところ、バリデーションは一瞬で終わりますが、実行はエラーになりました。後で--verbose
などでチェックしてみます。
🔗 benjdd.com/languages2: プログラミング言語の速度比較サイト
Visual and hyperfine results here: https://t.co/L9Aosn5fou
Github repo here: https://t.co/KsVtKIl0Ru
— Ben Dicken (@BenjDicken) December 3, 2024
つっつきボイス:「プログラミング言語の速度を比較するという、よくあるサイトですが、ちょうどRubyKaigi 2025でもZJITのMaximaさんが以下のバージョン↓をネタとして軽く引き合いに出していました」「話のタネにする分には楽しいヤツですね」
「FORTRANが意外に上位にいるけど、こういうのはコンパイラの性能次第で大きく変わりがち」「language2にはYJITありのRubyも追加されてますね」「Kotlinは実質Javaだけあって同じぐらい速い」「単純なループはCやRustがやはり強い」
「あれ、このBunってnpmみたいなJavaScriptのパッケージマネージャかと思っていたけど、言語でしたっけ?」「公式サイトを見ると、JSランタイムも含めたオールインワンとなっていますね↓」「Bunにランタイムも入っているとは知らなかった...」
参考: Bun — A fast all-in-one JavaScript runtime
「Bunみたいなのがありなら、JRubyなども入れていいのでは」「JRubyはJavaのJVMで動くから速そうですよね」
参考: Home — JRuby.org -- 現在Ruby 3.4コンパチブルと表示されています
今回は以上です。
バックナンバー(2025年度第2四半期)
週刊Railsウォッチ: bin/ciが追加、HashWithIndifferentAccessへの変換がスキップ可能にほか(20250409)
- 20250319 bundlerのbinstub生成を廃止、RubyのZJITほか
- 20250130 Railsコンソールの便利技、ruby-refrigerator gemほか
- 20250123 RailsガイドがRails 8.0.1に対応ほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)