こんにちは、hachi8833です。Rails 7.1beta1の全Changelog、あと少しで読み終われそうです。
🔗Rails: 先週の改修(Rails公式ニュースより)
🔗 生成される.dockerignoreに.envファイルを追加
重要なトークンを含む可能性のある.envファイルがあるかどうかをチェックせずに済むようになる。
同PRより
# railties/lib/rails/generators/rails/app/templates/dockerignore.tt#L9
+# Ignore all environment files (except templates).
+/.env*
+!/.env*.erb
同Changelogより
つっつきボイス:「DHHのシンプルなプルリクです」「たしかに.envは.dockerignoreにも含めておくべき」「!/.env*.erb
となっているのはテンプレート(.erb)ファイルを除外しないためみたい」「/.env*
だけで十分な気もしますけどね」
参考: .dockerignore ファイル -- Dockerfile リファレンス — Docker-docs-ja 24.0 ドキュメント
🔗 関連付けでprimary_key:
オプションを常に優先するようになった
このプルリクは、関連付けられるモデルに
query_constraints
が設定されている場合に、primary_key:
オプションが無視される問題を修正する。修正後は、常にprimary_key:
オプションが優先されるようになり、primary_key:
オプションが存在しない場合のみquery_constraints
でassociation_primary_key
の値が決定される。これは技術的にはRails 7.1 beta版のバグなので、CHANGELOGエントリとコミットが
7-1-stable
ブランチに(このブランチがあれば)バックポートされることを想定している。これを次のリリースでバグ修正として含める方法や、CHANGELOGエントリが必要かどうかについて知らせて欲しい。
同PRより
つっつきボイス:「Rails 7.1の複合主キー関連のバグ修正ですね: association_primary_key
で主キーを決定するときに、修正前はquery_constraints
が効いてしまっていたのを修正後はprimary_key
オプションを先にチェックするようになった↓」
# activerecord/lib/active_record/reflection.rb#L864
def association_primary_key(klass = nil)
- if !polymorphic? && ((klass || self.klass).has_query_constraints? || options[:query_constraints])
- (klass || self.klass).composite_query_constraints_list
- elsif primary_key = options[:primary_key]
+ if primary_key = options[:primary_key]
@association_primary_key ||= -primary_key.to_s
+ elsif !polymorphic? && ((klass || self.klass).has_query_constraints? || options[:query_constraints])
(klass || self.klass).composite_query_constraints_list
+ elsif (klass || self.klass).composite_primary_key?
# If klass has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
primary_key = (klass || self.klass).primary_key
primary_key.include?("id") ? "id" : primary_key
else
primary_key(klass || self.klass)
end
end
🔗 Active Recordのトランザクションをinstrumentationで計測できるようになった
Active Recordのトランザクションでinstrumentationを利用可能になった。
トランザクションイベントをサブスクライブすることでトラッキングやinstrumentationで利用できるようになる。イベントペイロードには、コネクションの他にタイミングの詳細詳細情報も含まれる。
ActiveSupport::Notifications.subscribe("transaction.active_record") do |event| puts "Transaction event occurred!" connection = event.payload[:connection] puts "Connection: #{connection.inspect}" end
Daniel Colson, Ian Candy
同CHANGELOGより
つっつきボイス:「transaction.active_record
というフックがinstrumentationに追加されたそうです」
参考: Active Support の Instrumentation 機能 - Railsガイド
「追加されたフックを見ると、handle
とstarted
とpayload
が取れるらしい↓」「ちなみにこのフックは7.1のガイドにはまだ追加されていませんでした」
class TransactionInstrumenter
def initialize(payload = {})
@handle = nil
@started = false
@payload = payload
end
def start
return if @started
@started = true
@handle = ActiveSupport::Notifications.instrumenter.build_handle("transaction.active_record", @payload)
@handle.start
end
def finish
return unless @started
@started = false
@handle.finish
end
end
「instrumentationは自分で追加することも可能だし、Datadogなどの監視サービスを使うのももちろんありですが、公式に追加されたことでトランザクションでこういう項目を調べやすくなったのはいいですね👍」
参考: クラウド時代のサーバー監視&分析サービス | Datadog
🔗 rails new
でBunを指定できるようになった
rails new --javascript
でBunをサポートするようになった。rails new my_new_app --javascript=bun
Jason Meller
同CHANGELOGより
関連プルリク
このプルリクは、以下の関連プルリクがすべてマージ・リリースされてからマージすること。さもないと
--javascript bun
が期待通り動かない。
- Add Bun support jsbundling-rails#167
- Add lockb diffing support for Bun jsbundling-rails#171
- Add Bun support cssbundling-rails#130
- Use bun for installation if applicable hotwired/turbo-rails#494 -- オープン(編集部注: その後マージされました)
- Use bun for installation if applicable hotwired/stimulus-rails#125 -- オープン
なお、ボーナスとしてexecJSを更新した(#127)ので、execJSでもBunをランタイムとして使えるようになった。
Bunについて
Bunは、node.jsランタイム、yarnパッケージマネージャー、esbuildバンドラーに対する有望な新しい代替手段。Bunの主な特徴は速さにあり、多くの場合node.jsや関連製品よりも数倍高速。
素のRailsプロジェクトのほとんどが、ほんの少しだけJSを散りばめたいと考えている(しかしJSエコシステムがimport-mapsよりもう少しましになる方が嬉しい場合もある)。Bunはこうした用途に非常に適しており、新しいRailsプロジェクトでも手軽に採用できる。
Stimulus、Turbo、Tailwindなどの共通のデフォルトを利用する新規Railsプロジェクトとの相性が実によいので、こうしたアプリを構築する人々向けに、Bunを第一級市民にすることを提案する。Bunでこれらのプロジェクトを手早く立ち上げられるようにして、Yarn/Nodeの残り物を外科手術で取り除く時間をかけずに済むようにすべき。
BunとTailwindの実行例
このプルリクがマージされれば、
rails new --javascript bun --css tailwind --database sqlite3
のようなオプションで新規Railsプロジェクトを立ち上げれば、「すべて問題なく」動くようになるはず。
同PRより
つっつきボイス:「最近人気が高まっているというBunが追加されました」「Bunはパッケージ管理以外にもバンドルやランタイムなどを単体でひととおりサポートしているんですって」「速いという評判」「bunを辞書で見るといくつか意味があるけど、アイコンからするとこの場合は"束髪"かな」
参考: Bun — A fast all-in-one JavaScript runtime
"BunとNodeの違いは、Bunがランタイムであるだけでなく、バンドル、タスクランナー、TSコンパイラーなど、すべてを1つの場所にまとめていることだ。"
» The bun that’s been in the oven — https://t.co/542ueyAysh | by Thomson Martin | Sep, 2023 | Medium https://t.co/GSyTS78Hog
— Otsuka (@mopin) September 19, 2023
「試しに7.1beta1でrails new --javascript bun --css tailwind --database sqlite3
をやってみたところ、rails new
は成功しましたが、周辺gemでまだマージされていないものがあるので、scaffoldしたページではまだJavaScriptが動きませんでした」
「業務で使うことを考えると、速さよりも今後長期間サポートされるかどうかの方を気にしたい」「結局そこがポイントですよね」
なお、Bunはjsbundling-rails環境での利用が前提なので、当然ながらimportmap-railsとは共存できません。
🔗 マイグレーションヘルパーで複合主キーをサポート
マイグレーションヘルパーで複合主キーをサポート。
# "carts"テーブルの主キーが"(shop_id, user_id)"だとする add_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id]) remove_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id]) foreign_key_exists?(:orders, :carts, primary_key: [:shop_id, :user_id])
fatkodima
同CHANGELOGより
つっつきボイス:「Rails 7.1で複合主キーをサポートするなら当然マイグレーションでもサポートが必要ですね: primary_key:
に複合主キーを配列の形で渡せるようになった👍」「これないと困るヤツ」「7.1beta1が出たこの時期でこういう機能が入ってくるぐらいなので、複合主キーはリリース後も使いながら完成度を高めていく形で進めることになるでしょうね」
🔗 マイグレーションのadd_check_constraint
にif_not_exists
オプションを渡せるようになった
マイグレーションにCHECK制約を追加するときの
if_not_exists
オプションをサポート。add_check_constraint :posts, "post_type IN ('blog', 'comment', 'share')", if_not_exists: true
Cody Cutrer
同CHANGELOGより
つっつきボイス:「以下のようなマイグレーションでバリデーションをオフにすると、1回目はいいけど2回目だとCHECK制約がもうできているのでエラーになってしまう: if_not_exists: true
を指定すると、CHECK制約が既に存在する場合でもadd_check_constraint
がエラーにならなくなる、なるほど」「デフォルトはif_not_exists: false
なんですね」
add_check_constraint
メソッドに新しいif_not_exists
オプションを渡せるようになった。
このオプションをtrue
に設定すると、CHECK制約が既に存在している場合でもエラーが発生しなくなる。
さらに、remove_check_constraint
やadd_check_constraint
にこのオプションが設定されていれば、マイグレーションの取り消し(ロールバック)でif_exists
およびif_not_exists
オプションの振る舞いも入れ替わる。これにより、冪等かつトランザクショナルでないマイグレーションを手軽に作れるようになる。動機/背景
自分たちは以下のようなマイグレーションを書くことが多い。
class MyMigration < ActiveRecord::Migration[7.0] disable_ddl_transaction! def change add_check_constraint(:table, "expression", name: "mychk", validate: false) validate_constraint(:table, "mychk") end end
しかし、バリデーションが失敗したときでもマイグレーションを気軽に再実行できるようにしたい。この操作はトランザクショナルではないので、そのためには冪等でなければならない。つまり、
add_check_constraint
にif_not_exists
オプションが必要となる。
また、トランザクショナルでないマイグレーション内で正しくロールバックするには、ロールバックでremove_check_constraint
を呼び出すときにif_exists: true
を設定する必要もある。
なお、CHECK制約の削除中にロールバック処理がデータベースから切断されると、その状態でマイグレーションが「完了」と記録される可能性がある(少々わざとらしい例だが、同じマイグレーション内でCHECK制約を追加してから削除する場合などに起きうる)。同PRより
🔗 暗号化属性の平文データサポートをsupport_unencrypted_data
オプションで属性ごとに無効化できるようになった
属性ごとに設定される
support_unencrypted_data
オプションを暗号化に追加。特定の暗号化済み属性についてのみ、暗号化されていない文のサポートを
support_unencrypted_data
でオフにできるようになった。
このオプションは、ActiveRecord::Encryption.config.support_unencrypted_data == true
が設定済みの場合にのみ有効。class User < ActiveRecord::Base encrypts :name, deterministic: true, support_unencrypted_data: false encrypts :email, deterministic: true end
Alex Ghiculescu
同CHANGELOGより
つっつきボイス:「なるほど、Railsの暗号化機能は、暗号化したい属性に既存の平文(暗号化されていない文)が既にある場合に読み出せるようにもできるんですが、その平文サポートを属性単位で無効にできるようになったということですね」「コンフィグのencryption.support_unencrypted_data
で平文のサポートをグローバルに許可している場合にのみ使えるとあるけど、これ自体オプショナルだからデフォルトではオフ」「平文をサポートしない属性はエラーにするのではなく平文を検索できなくなるのね↓」
test "If support_unencrypted_data is opted out at the attribute level, cannot find unencrypted data" do
UnencryptedBook.create! name: "Dune"
assert_nil EncryptedBookWithUnencryptedDataOptedOut.find_by(name: "Dune") # core
assert_nil EncryptedBookWithUnencryptedDataOptedOut.where("id > 0").find_by(name: "Dune") # relation
end
参考: § 3.5 暗号化されていないデータのサポート -- Active Record と暗号化 - Railsガイド
ActiveRecord::Encryption.config.support_unencrypted_data == true
に設定されている場合、以下のように書けるようになる。class User < ActiveRecord::Base encrypts :name, deterministic: true, support_unencrypted_data: false encrypts :email, deterministic: true end
この場合、
extend_queries: true
が設定されていれば、
この機能が欲しくなる理由についての裏話は#49072のコメントを参照。
同PRより
🔗 名前が衝突する属性名を生成するとエラーを発生するようになった
- PR: Raise error when generating attribute with dangerous name by p8 · Pull Request #47752 · rails/rails
属性名が衝突する危険がある場合にエラーをraiseするようになった。
以下のコマンドは、
save
とhash
が既にActive Recordで定義済みなのでエラーになる。bin/rails generate model Post save bin/rails generate model Post hash
Petrik de Heus
同CHANGELOGより
つっつきボイス:「危険な名前、たしかに」「この使っちゃいけない名前リストってどこにあるんでしょう?」(しばらく探す)「これみたい↓: なるほど、instance_methods
でリストを取り出しているんですね」
# activerecord/lib/active_record/attribute_methods.rb#L31
class << self
def dangerous_attribute_methods # :nodoc:
@dangerous_attribute_methods ||= (
Base.instance_methods +
Base.private_instance_methods -
Base.superclass.instance_methods -
Base.superclass.private_instance_methods
).map { |m| -m.to_s }.to_set.freeze
end
end
参考: Module#instance_methods
(Ruby 3.2 リファレンスマニュアル)
🔗 ドキュメント関連
🔗 複合主キーガイドが新たに追加
つっつきボイス:「新機能である複合主キーのガイドは欲しくなるヤツ👍: 今後ブラッシュアップされるんでしょうね」
参考: rails/guides/source/active_record_composite_primary_keys.md at main · rails/rails
🔗 テストガイドにビューパーシャルのテスト方法を追加
つっつきボイス:「こちらはテスティングガイドにパーシャルのテスト方法が追加されていました↓」「render partial:
ができるんだから、パーシャルのテストのドキュメントがあってもいいですね👍」
参考: rails/guides/source/testing.md at main · rails/rails
「なお、最近の更新ではありませんが、エラーレポートガイドも7.1で新しく追加されています↓」
参考: rails/guides/source/error_reporting.md at main · rails/rails
前編は以上です。
バックナンバー(2023年度第3四半期)
週刊Railsウォッチ: Turbo 8のTypeScriptがJavaScriptに置き換わるほか(20230914後編)
- 20230913前編 Active Recordのenumにエラーをraiseしないvalidateオプションが追加ほか
- 20230908後編 IRB 1.8.0でデバッグ機能強化、Ruby Prize 2023開催決定ほか
- 20230906前編 システムテストでPlaywrightをサポート、to_paramのデリミタを変更可能にほか
- 20230829前編 Active Storageのミラーアップロードが非同期に、Rackアプリを手作りほか
- 20230824後編 週刊Railsウォッチ: ArelでCAST関数サポート、webdrivers依存を解消、YJIT高速化ほか
- 20230823前編 Rails 7.0.7に含まれているRails 7.0.6のバグ修正ほか
- 20230809 Rails 7.0.5のcreate_association挙動変更取り消し、YJITの性能を最大限引き出す方法ほか
- 20230803後編 Railsフラグメントキャッシュ経由の情報漏洩に注意ほか
- 20230802前編 Active Storageバリアントの事前変換、Linkヘッダープリロードのオプトアウトほか
- 20230727後編 Rubyにdefp導入の提案、IRB 1.7.3リリースほか
- 20230725前編 config.autoload_libとconfig.autoload_lib_onceが追加ほか
- 20230721後編 Kaigi on Rails 2023プロポーザル募集、rubocop-magic_numbersほか
- 20230719前編 複合主キー関連の実装進む、Action TextでHTML5サニタイザほか
- 20230705後編 AWS LambdaでRailsをRackで動かすLambyほか
- 20230704前編 productionのforce_ssl=trueがデフォルトで有効に、rakeタスクをthorで書くほか
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)