Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 7.1に入る主要な機能まとめ(3)Docker関連ファイル導入ほか(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。原文の目次は省略しました。また、週刊Railsウォッチの該当項目へのリンクも追加してあります。

Rails 7.1に入る主要な機能まとめ(3)Docker関連ファイル導入ほか(翻訳)

以下は本シリーズの他の回へのリンクです。

「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.handleRails.error.recordに追加されたエラークラスのリストを渡す機能は、完全に後方互換性があります(#46299)。これによってErrorReporterが複数のエラークラスを一度に扱えるようになりました。今後は以下のような感じで複数のエラークラスを扱えるようになります。

Rails.error.handle(ArgumentError, TypeError) do
  # 何かエラー処理をする
end

参考: 週刊Railsウォッチ20221101

02. 🔗 check_box_tagと radio_button_tagcheckedがキーワード引数としても指定可能になった

#45527は、過去のAPIドキュメントの修正といくつかの改良に関連しています。
たとえばcheck_box_tag "admin", "1", checked: falseのように書けばチェックボックスのチェックが外れそうに思えますが、この書き方では期待通りに動きません。このプルリクはその点を修正します。

さらに、check_box_tagと radio_button_tagcheckedを位置引数(positional argument)としてもキーワード引数としても利用できるよう更新し、check_box_tagと radio_button_tagのAPIドキュメントも改善されました。

参考: 週刊Railsウォッチ20221115

03. 🔗  request.parameter_filterがpublicメソッドになった

リクエストでハッシュの値をフィルタするのに用いられるActiveSupport::ParameterFilterオブジェクトが公開され、リクエストと同じパラメータフィルタでハッシュをフィルタできるようになりました(#46280)。これによって、以下のようなマジックが使えるようになります。

request.parameter_filter.filter ("secret" => "skrt", "name" => "Manny")
#=> { "secret" => "[FILTERED]", "name" => "Manny" }

参考: 週刊Railsウォッチ20221115

04. 🔗 schema.rbの外部キーやCHECK制約にvalidate: falseを追加するようになった

従来は、外部キーやCHECK制約を追加したときにvalidate: falseが指定されていたかどうかという情報がschema.rbファイルに記録されていませんでした。そのため、データベースをスキーマからリストアするときに、バリデーションすべきでない外部キーやCHECK制約がバリデーションされてしまうことがありました。

#46339によって、外部キーやCHECK制約をバリデーションすべきでない場合にschema.rbファイルのadd_foreign_keyt.check_constraintvalidate: falseを含めるよう更新されました。これによってデータベースが適切にリストアされるようになり、外部キーやCHECK制約が誤ってバリデーションされないようになりました。

参考: 週刊Railsウォッチ20221115

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でいつでも変更可能です。

参考: 週刊Railsウォッチ20230131

06. 🔗 preloadeager_loadされた関連付けをunscopeできるようになった

Active Recordのincludesselectjoinsの場合と同様の形で、プリロードされた関連付けやeager loadingされた関連付けをunscopeする機能が導入されました(#45147)。この機能によって、既存のクエリでeager_loadpreloadを介して明示的に読み込み済みのhas_many関連付けに対して集約関数を適用できるようになります。

query.unscope(:eager_load, :preload).group(:id).select(:id)

参考: 週刊Railsウォッチ20221129

07. 🔗 ActiveRecord::Persistencebuildメソッドが追加された

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

参考: 週刊Railsウォッチ20221206

08. 🔗 YAMLシリアライズのオプションを属性ごとに設定可能になった

config.active_record.yaml_column_permitted_classes(デフォルトは[Symbol])はRailsアプリケーション全体で設定されます。今回、YAMLのシリアライズオプションを属性ごとに設定する機能が追加されました(#45660)。

訳注

#45660の実際のマージは4a07553で行われました。

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によって、requiredmultiplesizeというHTML属性を上記のどちらの形式でも渡せるようになりました。

12. 🔗 production環境でassets:precompileRAILS_MASTER_KEYなしで実行できるようになった

多くのRails開発者を悩ませていた古いissue #32947が修正されました(#46760)。この修正は5年越しでしたが、これによってproduction環境でイメージをビルドするときに、本物のRAILS_MASTER_KEYを渡さずにアセットをコンパイルできるようになりました。具体的には、development環境やtest環境と同様に、production環境でもENV["SECRET_KEY_BASE_DUMMY"] = 1でダミーのsecret_key_baseを渡せるようになりました。本物のcredentialやメッセージ検証にはアクセスできなくなりますが、これらはいずれにしろ通常は不要なので、ビルドを完了できるようになります。

参考: 週刊Railsウォッチ20230125

13. 🔗 'docked' Rails CLIが追加された

Railsが初めての人にとって、Railsのインストールとセットアップという最初の障壁を乗り越えるのはひと苦労です。多くの人が最初に何をすればよいのかもわからないまま、Railsを試すことを完全に諦めてしまうこともあるでしょう。

rails/docked - GitHub

Railsエコシステムに加わった新たなdockedツールは、そうした苦労を解消することを目的としています。dockedによって、Railsおよび必要なすべての依存関係をDockerコンテナにインストールする手順がシンプルになり、好奇心の旺盛な人たちが基本的なRailsアプリケーションを手早く構築できるようになります。

参考: 週刊Railsウォッチ20230125

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

参考: 週刊Railsウォッチ20230207

15. 🔗 ENVをチェックする最新のRails.env.local?メソッドが追加された

development環境またはtest環境であるかどうかのチェックがRails 7.1でひとつにまとめられました(#46786)。

if Rails.env.local?
  # 何かする
end

# 以下のように書かなくてもよくなる
if Rails.env.development? || Rails.env.test?
  # 何かする
end

参考: 週刊Railsウォッチ20230125

16. 🔗 ActiveRecord#enumのメソッド生成を無効にするオプションが追加された

ActiveRecord::Enumenumメソッドが導入されたのが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ウォッチ20230207


Rails 7.1の主要な新機能シリーズでは、Railsフレームワークの新バージョンで最も注目したい更新内容をいくつか取り上げました。すべての更新内容を網羅しているわけではありませんが、機能の重要性の大きさとインパクトを元に機能を選びました。

本記事は Hacker Newsに掲載され、いくつもの所見や洞察がそこから生まれました。

以上で本シリーズを終わりたいと思います。お付き合いいただいた皆さんに感謝申し上げます。また、522人の全コントリビュータにRailsコミュニティから心より感謝いたします。

RubyやRailsの最新情報を追いかけたい方は、元記事末尾のフォームでニュースレターを購読いただければ興味深い関連トピックを折に触れて配信いたします。

関連記事

Rails 7.1に入る主要な機能まとめ(1)update_attribute!、CTEサポートほか(翻訳)

Rails 7.1に入る主要な機能まとめ(2)error_highlight対応、routes --grepほか(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。