ActiveRecord::Base#pluck accepts hash values, devcontainers improvements and more! | This Week in Rails
ActiveRecordに関する変更です
ActiveRecordの pluck メソッドの引数にハッシュを渡せるようになりました
pluckメソッドは引数に受け取ったカラムをテーブルからSELECTする際に使います
code:rb
Person.pluck(:name)
これまでは、JOINしたテーブルのカラムを取得する際にはテーブル名とカラム名をドット記号でつなぎ合わせた文字列を引数に渡す必要がありました
code:rb
# Before
Post.joins(:comments).pluck("posts.id", "comments.id", "comments.body")
今回の変更後はテーブル名をキーとするHashを渡すことができるようになりました
文字列で指定するよりも構造的で、扱いやすくなったといえそうですね
code:rb
# After
ActiveRecordに関する変更です
strict_loading! というメソッドがあります
strict_loading!(value = true, mode: :all)
strict_loading モードを有効化すると、レコードが関連付けを遅延読み込みしようとしたときにエラーが発生します
code:rb
user = User.first
user.strict_loading! # => true
user.address.city
# => ActiveRecord::StrictLoadingViolationError
# user に紐づく関連付けである address を事前に読み込んでいないためエラーとなる
またキーワード引数の mode には :all または :n_plus_one_only を指定できます
:n_plus_one_only を指定した場合は、N+1問題の発生につながる関連付けを遅延読み込みしようとしたときにエラーが発生します
code:rb
user.strict_loading!(mode: :n_plus_one_only)
user.address.city # => "Tatooine"
# ↑はN+1にならないので遅延読み込みをしてもエラーにならない
user.comments.first.ratings.to_a
# => ActiveRecord::StrictLoadingViolationError
今回のプルリクエストでは、n_plus_one_only モードで有効化した場合における変更を行っています
具体的には、n_plus_one_onlyモードでstrict_loadingを有効化したインスタンスについて、1対多の関連付けを読み込む際に、取得したデータの順序が定まらない、という問題がありました。具体的なコードをみてみましょう:
code:rb
person = Person.find(1)
person.strict_loading!(mode: :n_plus_one_only)
person.posts.first
# SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
これに対して今回の変更では順序が一意に定まるようになりました(主キーの順で並ぶようになりました)
code:rb
person = Person.find(1)
person.strict_loading!(mode: :n_plus_one_only)
person.posts.first # this is 1+1, not N+1
# SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
ActionPackに関する変更です
テストコード用のヘルパーメソッドとして save_and_open_page が追加されました
インテグレーションテストのコード内でこのメソッドを呼び出すことで、レンダリングされるHTMLをファイルとして保存してブラウザで開いてくれます
code:rb
class ApplicationController < ActionController::Base
def index
render plain: "hello world!"
end
end
code:rb
require "test_helper"
class ApplicationControllerTest < ActionDispatch::IntegrationTest
test "save and open" do
get root_path
save_and_open_page
end
end
開発者がインテグレーションテストの動作検証をする際に役立ちそうですね