1. tanaken on Rails
  2. #016: pluck, strict_loading!..
2024-04-21 19:37

#016: pluck, strict_loading!, save_and_open_page

00:01
こんにちは。第16回のTanaken on Railsです。今回もThis Week in Railsから、3つプリリクエストをピックアップします。
1つ目、Allow ActiveRecord://base-sharp-pluck to accept hash values。
pluckで読み方はあっているかな。pluckかな、発音記号を見ると。pluckだと思います。
こちらのプリリクエストは、アクティブレコードに関する変更です。
アクティブレコードのpluckメソッドの引数に、ハッシュを渡せるようになりました。
pluckメソッドは、引数に受け取ったカラムをテーブルからセレクトする際に使いますね。
APIドキュメントを貼っておきます。
例えばpersonというモデルがあったときに、person.pluck括弧でシンボルネーム。
引数はシンボルでもストリングでも大丈夫ですね。
例えばこのperson.pluck括弧でシンボルネームだと、ネームカラムをpersonsテーブルから取得するよという感じですね。
これまではジョインしたテーブルのカラムを取得する際には、
テーブル名とカラム名をドット記号でつなぎ合わせた文字列を引数に渡す必要がありました。
例えばpostというモデルがあって、postにひも付くcommentsというモデルがある場合に、
post.joins括弧でcomments.pluck括弧で引数の話ですね。
ストリングでpost.idだったり、第2引数でcomments.id、コメントのIDを取ってくると。
第3引数でcomments.body、コメントのbody本文を取ってくるよというようなpluckメソッドに。
pluckメソッドの引数は文字列かシンボルの配列を渡せるという感じになっているので、
post.id、comments.id、comments.body、この3つを渡している例として今回書いてみています。
文字列でpost.idという文字列を渡したらpostのIDが取れるよみたいな感じが今まででした。
今回のプリリクエストの変更後は、引数にテーブル名をキーとするハッシュを渡すことができるようになっています。
03:07
先ほどの例だとpost.joins comments.pluck括弧で引数にpostsコロン、
postsをキーとすハッシュでpostsコロン書き括弧でブラケットかハブラケットで中にコロンID。
コメンツブラケットでID、bodyという感じで渡せるようになりました。
こういうふうに引数をハッシュで渡せるようになったので、文字列で渡すときと同じことができるし、
より構造的に文字列で渡すとどうしても書き間違いとか文字列というオブジェクトになっちゃっていると
取り回しがちょっとしにくかったりする部分もあったかもしれないなと思うんですけど、
ハッシュにすることでより構造的にわかりやすくなったというところがメリットかなと思います。
というのが一つ目のプリリクエストでございました。
続いて二つ目、Fixed Child Association Loading in N plus 1 Only Modeというプリリクエストです。
こちらもActiveRecordに関する変更です。
ActiveRecordにStrictLoadingBickeringというメソッドがあります。
Strict Underscore Loading Bickeringというメソッドですね。
まずこれの説明をしておきます。
第一引数はValueで、デフォルトの値がTrue。
第二引数がModeですね。デフォルトの値がシンボルのAllというメソッドです。
このStrictLoadingModeというのを有効にできると、このメソッドを使うとできるという感じですね。
このStrictLoadingというモードは何なのかというと、
レコードが関連付けを遅延読み込みしようとしたときにエラーが発生するというモードですね。
StrictLoadingModeというのはそういうモードです。
ちょっと具体例を見てみましょう。
小文字のユーザーという変数を定義します。
userイコール大文字のユーザーモデルからFirst、一つ目のレコードを取っていきます。
06:03
その小文字のユーザーの変数、ユーザーモデルのインスタンスに
メソッドチェーンでStrictLoadingびっくりというのをやると、
これでStrictLoadingModeが有効になった状態ですね。
この状態で、例えばユーザーモデルに紐づくアドレスというレコードを取ってくると、
user.addressという形でレコードを取ってきて、
例えばそのアドレスのcityというアトリビュートを表示してみましょうと。
そんな感じのコードを書いてみると、
ActiveRecordStrictLoadingViolationErrorというのが発生します。
これはユーザーに紐づく関連付けであるアドレスというモデルのデータを
事前に読み込んでいないため、エラーが発生するということですね。
これを回避するためには、
userイコールユーザー.firstというふうに定義したときに、
この段階でuser.preload括弧でアドレスで.firstというのをやっておくと、
最初にpreloadとかincludeとかeggerloadとか手段は何でもいいと思うんですけど、
アドレスも読み込んで、事前に読み込んでおくというふうにすれば、
StrictLoadingModeをonにしても、
エラーにならないということですね。
こういうActiveRecordの場合は、
例えばuser.addressとかってやったときに、
ユーザーに紐づくアドレスモデルのレコードを後から読み込むということを
仕組みとしてやってるんですよね。
それを遅延読み込みというふうに呼んでるんですけど、
その遅延読み込みを事前に分かってやっておくのと、
後からたまたま呼び出したときに読み込みされてっていうのだと、
開発者目線でいう最初に定義したときに分かってるのか、
読み込む前提で定義してるのか、
後からたまたま呼び出されてるのかっていうのは、
またちょっと意味合いが変わってきますよね。
後から読み込む遅延読み込みっていうのをやると、
それが問題でパフォーマンスに、
予期せぬ読み込みがあってパフォーマンスに影響があるってことが
あったりするわけなんですよね。
なのでストリクトローディングというのをオンにすることで、
後出しで遅延読み込みしたことに気づけるようになってるということですね。
そういうモードがあります。
もう少しこのストリクトローディングについて説明を加えると、
キーワード引数のモード。
このモードはシンボルでALLという値がデフォルトになってるんですけど、
09:00
それ以外にはNプラス1オンリーというモードを指定することもできます。
Nプラス1オンリーっていうのを指定した場合は、
Nプラス1問題の発生につながるような関連付けを遅延読み込みしたときに
エラーが発生するようになります。
なので先ほどの例のような、ユーザーストリクトローディングであるんですけど、
ユーザーのメソッドチェーンしてストリクトローディングびっくり。
そこでモードNプラス1オンリー、Nプラス1問題が発生する場合のみっていうモードで
ストリクトローディングを有効化すると。
その場合は先ほどの例のユーザー.アドレス.シティとかっていう風にやっても
エラーにはなりません。
これはNプラス1問題にユーザーからただアドレスを引いてくるだけであれば
別に問題にならないよねということですね。
はい。問題になりそうなのはユーザーから複数1台ただひも付いているような
関連付けを呼んで、そこからさらにその関連付けにひも付く別の関連付けを呼ぶ
みたいなときはNプラス1になるよねということを言っています。
例えば先ほどの例だと、先ほどの例というか新たな例、ユーザーモデルに対して
ユーザーモデルがコメンツという関連付けを持っているとしましょう。
ユーザー.コメンツとかってやると、ユーザー.コメンツ自体は
ユーザーIDをキーにしてコメンツレコードからレコードを取ってくるだけなんで
それ自体はエラーにならないんですけど
例えばユーザー.コメンツでコメンツ.ファースト
ユーザー.コメンツ.ファースト、ユーザーのコメントの1件目を取ってきますと
そのコメンツにひも付くまた別の関連付け
このAPIドキュメントの例では.レイティング
コメントに対してレイティングが評価みたいなのがあるという前提なのかな
レイティングというモデルをコメンツに対して
メソッドチェーンでレイティングを呼び出すというようなことをやると
1個のコメントに対してレイティングを毎回呼び出すってことが発生するので
これってnプラ1に問題につながるよねということなんで
コメンツ.ファースト.レイティングというふうにやったところで
アクティブレコードストリクトローディングバイオレーションエラー
っていうのが発生すると
なのでnプラス1オンリーの挙動はそんな感じですね
そういうストリクトローディングという仕組みがあるんですよと
今回のプルリクエストの話にやっと入るんですが
12:02
今回のプルリクエストではこのnプラス1オンリーモードの時に
ちょっと予期せぬ挙動
大した挙動ではないものがあったので変更しましたという話ですね
具体的には何かというと
このnプラスオンリーモードでストリクトローディングを有効化したインスタンスについて
1対他の関連図形を読み込むときに
取得したデータの順序が定まらない
実行するたびに変わる
実行するたびに変わるとも言い切れないけど
不定であると
1位に定まらないという順序がバラバラになり得るというのが問題があったと
具体的なコードを見てみます
今から紹介するコードはプルリクエストの方に記載されていたサンプルコードですね
パーソンというモデルがあるとしましょう
大文字のパーソンという変数にパーソンモデルのID1番のデータを格納すると
パーソンイコール大文字のパーソン.find1
パーソンにメソッドチェーンでパーソン.ストリクトローディングピックリップ
モードはnプラスオンリーモードでストリクトローディングを有効化すると
その状態でパーソン.post.first
パーソンに紐づく投稿ポストというレコードがあるとして
ポストモデルがあるとして
パーソン初めにポストなのかな
パーソン.post.firstとかやってやると
パーソンIDが1番のレコードをポストから取ってくると
というふうになるんですけど
順番が指定されていない
つまりオーダーバイ何
オーダーバイどの順番で並び替えするかというのが指定されていないので
どのレコードが取られるかというのが
そのときのDBの状態次第だったりすると
なので今回の変更では
オーダーバイを指定するように変更が入っていると
どういう順番で並ぶかというと
プライマリーキーの順番で並ぶようにした上で
レコードを取ってくるようになったよと
なので例えばさっきの
パーソン.post.firstとかってやると
セレクト文がセレクト.from.posts
fair.person.id.1で加えて
オーダーバイID.limit1という形で
15:00
IDで並び替えて1件取ってくるよと
そういうクエリが発行されるようになって
変更されてますよということですね
順番がちょっと変わっちゃうことによって
予期せぬ動きが起こっていたので
それを順番が揃うようになってますということでございますね
最後3つ目
Add Saved and Open Page Helper to Integration Test
アクションパックに関する変更です
テストコード用のヘルパーメソッドとして
Save and Open Pageというメソッドが追加されました
すべてアンダースコアつなぎですね
Save underscore and underscore open underscore page
というメソッドが追加されております
このメソッドはテスト用のヘルパーメソッドで
インテグレーションテストのコード内で
このメソッドを呼び出すことで
レンダリングされるHTMLをファイルとして保存して
ブラウザーで開くということをやってくれます
例えば アプリケーションコントローラーというのがあるとしましょう
アクションコントローラーベースを継承した
アプリケーションコントローラーがあって
インデックスアクションがあるとしましょう
インデックスアクションの中身では
プレインテキストとしてHello Worldをレンダリングしていると
そういうコントローラーとアクションがあるとしましょう
テストコードではどんなテストコードになるかというと
テストヘルパーをリクアイアしていて
アプリケーションコントローラーテストというのを定義します
アプリケーションコントローラーテストは
アクションディスパッチコロンコロンインテグレーションテストを継承している
インテグレーションテストとして
アプリケーションコントローラーテストを実装していると
テストの内容としては
例えばルートパスをゲットしていて
例えばこのルートパスが
アプリケーションコントローラーのインデックスに
振り分けられているという前提で
ルートパスを開くというようなテストをしていて
その下で今回追加されたメソッド
セーブアンドオープンページというメソッドを呼び出すと
このアプリケーションコントローラーのインデックスアクションで
レンダリングされているハローワールドというのが
htmlファイルとして保存されて
ブラウザでオープンされるようになると
18:02
そういうメソッドが追加されたということですね
このメソッドを活用することで
レールズアプリケーションの開発者が
インテグレーションテストの動作確認をするときに
役立つでしょうということを言っています
このプレリクエストの著者の方曰く
こういうインテグレーションテストの内容を
レンダリングされるhtmlファイルを保存して
ブラウザで開くというようなメソッドを
自前で実装しているプロジェクトを何度か見てきたと
だいたいみんなそういうふうにやってるんじゃないかということで
だったらレールズのテストヘルパーメソッドとして
追加しておけばいいんじゃないかということで
実装してくださったという話みたいですね
便利便利ということです
そんなところで今回はプレリクエストを3つ紹介しました
1つはアクティブレコードのブラックメソッドに関する変更
2つ目はアクティブレコードのストリクトローディングという
メソッドを使ったときのダービジョン オーダーバイを追加したよという話
3つ目がアクションパックでテスト用のヘルパーメソッド
セーブ&オープンページというのを追加されたよと
そんなお話をしました
ではこんなところで今回のたなけんオンレールズを終わりにします
ではまた来週バイバイ
19:37

コメント

スクロール