Rails 7.1に入る主要な機能まとめ(3)Docker関連ファイル導入ほか(翻訳)
以下は本シリーズの他の回へのリンクです。
- Rails 7.1に入る主要な機能まとめ(1)update_attribute!、CTEサポートほか(翻訳)
- Rails 7.1に入る主要な機能まとめ(2)error_highlight対応、routes –grepほか(翻訳)
「Rails 7.1に入る機能まとめ」シリーズは今回で最後です。Railsが長年に渡って改良を繰り返していることは言うまでもありませんが、私にとってこのマイナーバージョンが最もエキサイティングです。RailsにDockerfileが正式に組み込まれたという、思いがけないような話もあります。
今ならGemfileでRailsを以下のように指定すれば、Rails 7.1.0.alphaの機能をすべて試せます。
gem "rails", github: "rails/rails", branch: "main"
Rails 7.1を祝うべき17の理由を追加で紹介いたします。
01. 🔗 ErrorReporter
が複数のエラークラスを扱えるようになった
Rails.error.handle
とRails.error.record
に追加されたエラークラスのリストを渡す機能は、完全に後方互換性があります(#46299)。これによってErrorReporter
が複数のエラークラスを一度に扱えるようになりました。今後は以下のような感じで複数のエラークラスを扱えるようになります。
Rails.error.handle(ArgumentError, TypeError) do
# 何かエラー処理をする
end
02. 🔗 check_box_tag
と radio_button_tag
でchecked
がキーワード引数としても指定可能になった
#45527は、過去のAPIドキュメントの修正といくつかの改良に関連しています。
たとえばcheck_box_tag "admin", "1", checked: false
のように書けばチェックボックスのチェックが外れそうに思えますが、この書き方では期待通りに動きません。このプルリクはその点を修正します。
さらに、check_box_tag
と radio_button_tag
でchecked
を位置引数(positional argument)としてもキーワード引数としても利用できるよう更新し、check_box_tag
と radio_button_tag
のAPIドキュメントも改善されました。
03. 🔗 request.parameter_filter
がpublicメソッドになった
リクエストでハッシュの値をフィルタするのに用いられるActiveSupport::ParameterFilter
オブジェクトが公開され、リクエストと同じパラメータフィルタでハッシュをフィルタできるようになりました(#46280)。これによって、以下のようなマジックが使えるようになります。
request.parameter_filter.filter ("secret" => "skrt", "name" => "Manny")
#=> { "secret" => "[FILTERED]", "name" => "Manny" }
04. 🔗 schema.rbの外部キーやCHECK制約にvalidate: false
を追加するようになった
従来は、外部キーやCHECK制約を追加したときにvalidate: false
が指定されていたかどうかという情報がschema.rbファイルに記録されていませんでした。そのため、データベースをスキーマからリストアするときに、バリデーションすべきでない外部キーやCHECK制約がバリデーションされてしまうことがありました。
#46339によって、外部キーやCHECK制約をバリデーションすべきでない場合にschema.rbファイルのadd_foreign_key
とt.check_constraint
にvalidate: false
を含めるよう更新されました。これによってデータベースが適切にリストアされるようになり、外部キーやCHECK制約が誤ってバリデーションされないようになりました。
05. 🔗 production環境でPumaのワーカー数をプロセッサ数に合わせるようになった
Pumaのテンプレートにデフォルトで以下が含まれるようになりました(#46838)。
if ENV["RAILS_ENV"] == "production"
worker_count = ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count }
workers worker_count if worker_count > 1
end
新たに生成されるRailsアプリケーションのPumaワーカーは、デフォルトでホストの物理プロセッサ総数を上限とするようになりました。もちろんpuma.rbでいつでも変更可能です。
06. 🔗 preload
やeager_load
された関連付けをunscope
できるようになった
Active Recordのincludes
やselect
やjoins
の場合と同様の形で、プリロードされた関連付けやeager loadingされた関連付けをunscope
する機能が導入されました(#45147)。この機能によって、既存のクエリでeager_load
やpreload
を介して明示的に読み込み済みのhas_many
関連付けに対して集約関数を適用できるようになります。
query.unscope(:eager_load, :preload).group(:id).select(:id)
07. 🔗 ActiveRecord::Persistence
にbuild
メソッドが追加された
ActiveRecord::Persistence
モジュールがbuild
メソッドで拡張されました(#45696)。このメソッドは1つ以上のオブジェクトを作成してそれらを返します。属性パラメータへの入力は「ハッシュ」または「ハッシュを要素に持つ配列」のどちらかでなければならず、どちらの場合も、構成するオブジェクトの属性を含めておく必要があります。
以下にいくつかの利用例を示します。
# 新規オブジェクトを1個ビルドする
User.build(first_name: 'Jamie')
# 新規オブジェクトの配列をビルドする
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
# オブジェクトを1個ビルドしてブロックに渡す形で他の属性を設定する
User.build(first_name: 'Jamie') do |u|
u.is_admin = false
end
08. 🔗 YAMLシリアライズのオプションを属性ごとに設定可能になった
config.active_record.yaml_column_permitted_classes
(デフォルトは[Symbol]
)はRailsアプリケーション全体で設定されます。今回、YAMLのシリアライズオプションを属性ごとに設定する機能が追加されました(#45660)。
09. 🔗 単数形の関連付けをリセットできるようになった
コレクション関連付けActiveRecord::Associations::CollectionProxy
には、キャッシュされたクエリをリセットするreset
メソッドがあります。コード例を見てみましょう。
class Person < ActiveRecord::Base
has_many :pets
has_one :car
end
person = Person.first
# データベースからpetsをフェッチする
person.pets
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
# petsのキャッシュを利用する
person.pets
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
# petsのキャッシュをクリアする
person.pets.reset
# データベースからpetsをフェッチする
person.pets
# => [#<Pet id: 1, name: "Snoop", group: "dogs", person_id: 1>]
これと同じことをhas_one
関連付けとbelongs_to
関連付けでもできるようになりました(#46165)。これにより、オーナーモデルでreset_関連付け名
メソッドを呼び出せます。このメソッドは、キャッシュされた関連付けレコードをクリアし、次回アクセス時にはデータベースから読み込みます。上の例で言うと、Person
を使ってperson.car.reset_person
のように呼び出せるようになります。なかなかクールですよね?
10. 🔗 属性が変更されていないbelongs_to
関連付けのバリデーションを回避するようになった
この機能は他の機能ほどわかりやすくありませんが、それでも重要な機能です。
従来のActive Recordは、関連付けられた属性が変更されていない場合であっても、レコード更新時にbelongs_to
関連付けが存在するかどうかをチェックする不必要なクエリを実行していました。この点が改善されて、belongs_to
に関連するカラムについてのみ存在チェックを行うようになりました。ただしこの方法では孤立レコードが発生する可能性があるため、外部キー制約を用いてこの問題を防ぐことが推奨されています。
現状のクエリは以下のようになります。
post.update!(title: "Rails is the best")
TRANSACTION (0.1ms) BEGIN
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Post Update (0.3ms) UPDATE "posts" SET "title" = $1 WHERE "posts"."id" = $2 [["title", "Rails is the best"], ["id", 3]]
TRANSACTION (39.5ms) COMMIT
#46522によってクエリが以下のように改善されます。
post.update!(title: "Rails is the best")
TRANSACTION (0.1ms) BEGIN
UPDATE "posts" SET "title" = $1 WHERE "posts"."id" = $2 [["title", "Rails is the best"], ["id", 4]]
TRANSACTION (0.4ms) COMMIT
Railsは基本的に、変更がない場合にbelongs_to
関連付けのバリデーションを回避するようになります。
この振る舞いはconfig.active_record.belongs_to_required_validates_foreign_key = false
で変更できます(load_defaults 7.1
ではデフォルトで無効に設定されます)。
11. 🔗 f.select
呼び出しでオプションとHTMLオプションを1つのハッシュで渡せるようになった
select
メソッドの呼び出しで、select
のオプションと、いくつかのHTMLオプションを1つのハッシュとして渡せるようになりました。
従来は以下のコードが期待通りに動きませんでした。
<%= select :post, :author, authors, required: true %>
上のコードは以下のように呼ぶ必要がありました。
<%= select :post, :author, authors, {}, required: true %>
#46629によって、required
、multiple
、size
というHTML属性を上記のどちらの形式でも渡せるようになりました。
12. 🔗 production環境でassets:precompile
をRAILS_MASTER_KEY
なしで実行できるようになった
多くのRails開発者を悩ませていた古いissue #32947が修正されました(#46760)。この修正は5年越しでしたが、これによってproduction環境でイメージをビルドするときに、本物のRAILS_MASTER_KEY
を渡さずにアセットをコンパイルできるようになりました。具体的には、development環境やtest環境と同様に、production環境でもENV["SECRET_KEY_BASE_DUMMY"] = 1
でダミーのsecret_key_base
を渡せるようになりました。本物のcredentialやメッセージ検証にはアクセスできなくなりますが、これらはいずれにしろ通常は不要なので、ビルドを完了できるようになります。
13. 🔗 'docked' Rails CLIが追加された
Railsが初めての人にとって、Railsのインストールとセットアップという最初の障壁を乗り越えるのはひと苦労です。多くの人が最初に何をすればよいのかもわからないまま、Railsを試すことを完全に諦めてしまうこともあるでしょう。
Railsエコシステムに加わった新たなdockedツールは、そうした苦労を解消することを目的としています。dockedによって、Railsおよび必要なすべての依存関係をDockerコンテナにインストールする手順がシンプルになり、好奇心の旺盛な人たちが基本的なRailsアプリケーションを手早く構築できるようになります。
14. 🔗 RailsアプリケーションにデフォルトでDockerfileが含まれるようになった
新しいRailsアプリケーションでは、以下のDocker関連ファイルがデフォルトのオプションとして追加されるようになりました(#46762)。
Dockerfile
.dockerignore
bin/docker-entrypoint
これらのDocker関連ファイルは、アプリケーションをproduction環境にデプロイする場合の出発点とすることを意図しており、development環境で使用するべきではありません。ただし不要な場合は--skip-docker
オプションでDocker関連ファイルの追加をスキップできます。
実行例:
docker build -t app .
docker volume create app-storage
docker run --rm -it -v app-storage:/rails/storage -p 3000:3000 --env RAILS_MASTER_KEY=<see config/master.key> app
このDockerイメージからコンソールやランナーも実行できます。
docker run --rm -it -v app-storage:/rails/storage --env RAILS_MASTER_KEY=<config/master.keyを参照> app console
15. 🔗 ENV
をチェックする最新のRails.env.local?
メソッドが追加された
development環境またはtest環境であるかどうかのチェックがRails 7.1でひとつにまとめられました(#46786)。
if Rails.env.local?
# 何かする
end
# 以下のように書かなくてもよくなる
if Rails.env.development? || Rails.env.test?
# 何かする
end
16. 🔗 ActiveRecord#enum
のメソッド生成を無効にするオプションが追加された
ActiveRecord::Enum
でenum
メソッドが導入されたのがRails 4.1だったことを覚えていますか?このメソッドは enum
属性を宣言し、その値をデータベースのintegerに対応付けます。このとき、enum
属性を扱いやすくするためのメソッドが大量に生成されます。
つまり、以下のようなコードでは
class Conversation < ActiveRecord::Base
enum :status, [ :active, :archived ]
end
何もしなくても以下のすべてのメソッドが生成されます。
# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status # => "active"
# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status # => "archived"
しかし、これらのメソッド名はアプリケーションコードのメソッド名と衝突してしまうことがあります。#46490によって、enum
定義にinstance_methods
オプションが追加されました。このオプションをfalse
に設定すると、従来のActive Recordがデフォルトで生成していたそれらのインスタンスメソッドを生成しなくなります。
class Conversation < ActiveRecord::Base
enum :status, [ :active, :archived ], instance_methods: false
end
17. 🔗 HealthController
がデフォルトで追加されるようになった
#46936では、ロードバランサーやアップタイムモニタなどで利用できる新たなエンドポイントが導入されました。新規Railsアプリケーションでは、Rails::HealthController#show
メソッドが追加されてルーティングの/up
パスにマッピングされるようになります。ロードバランサーやアップタイムモニタは、この新たなエンドポイントでアプリの死活監視を手軽に行えるようになります。
ただし、データベース、Redis、アプリケーションが依存するマイクロサービスへの内部ネットワーク接続の監視が必要な場合は、別途監視を行う必要があります。
Rails 7.1の主要な新機能シリーズでは、Railsフレームワークの新バージョンで最も注目したい更新内容をいくつか取り上げました。すべての更新内容を網羅しているわけではありませんが、機能の重要性の大きさとインパクトを元に機能を選びました。
本記事は Hacker Newsに掲載され、いくつもの所見や洞察がそこから生まれました。
以上で本シリーズを終わりたいと思います。お付き合いいただいた皆さんに感謝申し上げます。また、522人の全コントリビュータにRailsコミュニティから心より感謝いたします。
RubyやRailsの最新情報を追いかけたい方は、元記事末尾のフォームでニュースレターを購読いただければ興味深い関連トピックを折に触れて配信いたします。
関連記事
Rails 7.1に入る主要な機能まとめ(2)error_highlight対応、routes --grepほか(翻訳)
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。原文の目次は省略しました。また、週刊Railsウォッチの該当項目へのリンクも追加してあります。