1. tanaken on Rails
  2. #008: assert_emails, WhereCh..
2024-02-25 17:31

#008: assert_emails, WhereChain#associated, filter_parameters

00:01
はい、こんにちは、たなけんです。第8回のTanaken on Rails、始めていきます。
今週はですね、This Week in Railsの更新がね、ちょっとね、遅くなりまして、
普段、金曜日の夜とか土曜日の朝ぐらいに更新されるんですけども、
土曜日、週日更新されず、日曜日の朝、何時ぐらいだったかな、に更新されたという感じだったんで、
それに合わせて収録もちょっと遅くなって、日曜日になってしまいました。
まあね、This Week in Railsに限らず、Railsのコミットログ見て、チェンジログ見てね、
気になったやつだけ読むっていう風にしてもいいかなとかもね、思ってるんですけど、
ちょっとThis Week in Railsをベースにやっていくって最初に決めたんで、
それに合わせてやっていこうかなというのが今のところの感じです。
今日ね、日曜日の配信になったんで、
次回からも日曜日のペースでやっていこうかなという気もしてます。
土曜日か日曜日に、週に1回ぐらいのペースで更新されると思っていただければいいかなと思います。
ということで、今回もプレリクエストの中から3つピックアップしてご紹介したいと思います。
まず1個目、タイトルがassert__emails://return the emails that were sentというタイトルのプレリクエストです。
こちらはアクションメーラーに関する変更です。
アクションメーラー__testhelperにassertemailsというメソッドがあります。
このメソッドは送信されたメールの数を検証する、assertionするメソッドです。
例えばtest__emails引数に0と渡すと、その直前までで何回メールが送られましたかという感じで、0回なんでtrueというかassertに成功する。
その後2行目で、例えばcontactmailerというものがあったとして、contactmailerのwelcomeというメールをdeliver now、メール送信今しましたと。
するとassertemails1って書くとtrueになると、assertに成功するというようなそういうメソッドですね。
今は引数に数字を渡す、0とか1とか渡すという例だったんですけど、ブロックを渡すこともできます。
ブロックを渡す場合は、そのブロック内でブロックの中でのメールの送信件数をチェックするというような動きになります。
03:05
なのでassert__emailsに引数で1渡して、その後do endで、そのブロックの中でcontactmailer.welcome.deliver nowみたいなね、
contactmailerのwelcomeメールを送るよというような処理をやったら、このブロックの中で1回だけメール送信処理があるので、
assertemailsに渡した1という値と付き合わせをして、1という値が期待されて1回メール送信したので、このassertionはパスすると。
テストクリアになるよというような、そんなメソッドですね。
今回のプールリクエストでは、このassertemailsメソッドにブロックを渡した場合の挙動が変わっています。
具体的には戻り値が変わっています。
この変更前は、このブロックを渡した場合でもassert="の結果を返していました。
最終的に、例えばさっきの例だと、1件、ブロックの中で1件送るよというのと、
実際に送ったブロックの中で実行されたメール送信の件数の1というのと、期待値の1と実際の1というのを比べてassertして、assert="というメソッドでassertして、
一致していれば、trueを返すのかな。
すみません。assert="のメソッドの戻り値はちょっと見てなかったんですけど、
多分、true返すのかな。
一致してない場合は、レイズするんですよね。例外を出すという感じだと思います。
例外というかテストを落とす。
落ちた理由のメッセージが出るみたいな感じになっていると思うんですけど、
そのassert="の結果を返していたというのが変更前です。
変更後は、このブロックを渡した場合に、
メールコロンコロンメッセージクラスのインスタンス、あるいはそのインスタンスが複数詰め込まれた配列というのを返すようになりました。
これ何が嬉しいかというと、assert="emails="メソッドにブロックを渡した時に、
メッセージクラスのインスタンスが返ってくることで、
メッセージの本文とかタイトルとかにアクセスできるようになるんですよね。
なので例えば、さっきの例でassert="emails1-do-contact-mailer.welcome-deliver-now-end."とかやった場合に、
このcontact-mailer-welcomeというメソッドでメールが送られるメールのメッセージとメールの本文とか、
送信先のメールアドレスとかもアクセスできるようになるはず。
06:04
なので、それ以降のassert="emails1-do-contact-mailer.welcome-deliver-now-end."のテストコードで、
タイトルのチェックとか本文のチェックとかという検証もできるようになるということですね。
で、それが便利だよということになります。
僕ね、このassert="emails1-do-contact-mailer.welcome-deliver-now-end."メソッドはね、実は使ったことなかったなと思ったんで、
これまあ、使っていきたい。そもそもね、使ったことなかったんで使っていきたいなと思ったし、
今回の変更で便利になったんで、ありがたいなという感じがしてます。
はい、というのが1個目でございました。
続いて2個目。タイトルがFixOverrideExistingJoinTypesInTheQueryInTheWhere.associatedMethodというタイトルです。
こちらはアクティブレコードに関する変更です。
アクティブレコード://querymethods://wherechainというクラスがあって、
このクラスにassociatedというメソッドがあります。
このメソッドは引数としてアソシエーションのシンボルを受け取ります。
その受け取ったアソシエーションを結合して、
結合したアソシエーションのIDがヌルじゃないレコードだけに絞り込んだリレーションを返します。
言葉だけだとなかなか難しいかもしれないんですけど、
具体例を言うと、例えば投稿するポストというモデルがあったとしましょう。
post.whereで、
where.hogehogeという形でチェーンすることができるというメソッドがあって、
もう一回頭から読むと、post.where.associated括弧シンボルのauthorというような式、
コードがあるという場合に、
postというモデルに対してauthorという投稿の著者ですよね。
authorというアソシエーションをシンボルで渡していると。
そうするとどんなクエリが発行されるかというと、
セレクトポスツフロムポスツで、
このポスツというテーブルにinnerjoin authors on authorsid="posts.authorsid".
09:04
なので、postのauthoridコラムとauthorsテーブルのidコラムというのを
内部結合すると。
最後に、where authorsidisnotnull。
なので、authorsのidがnullじゃないレコードだけに絞り込んで、
postとauthorがジョインできて、
authorのidがnullじゃないポスツを取ってくるよと。
そんなクエリがかけるわけなんですよね。
今回のプレリクエストで何が変わったかというと、
もともとこのプレリクエストの変更前は、
このassociatedというメソッドが既存の既に指定されている
結合の種類を上書きしてしまうという問題がありました。
例えば、今直前で紹介した例の場合に、
例に加えてポストモデルに対して、
明示的に外部結合が指定されていた場合というのを考えてみましょう。
例えば、post.leftouterjoinsというメソッドがありますね。
post.leftouterjoins括弧author
.whereassociated括弧authorとなった場合に、
明示的にleftouterjoinsauthorという形で、
オーサーを外部結合したいんだよというのが書いてあるにもかかわらず、
その以降でwhere.associatedというのを使うと、
オーサーをインナージョインする形で上書きされてしまうと。
なのでleftouterjoinsってせっかく書いてあったのに、
そいつが無視されてインナージョインが優先されてしまうと。
そういう挙動になっていましたということなんですね。
これだとせっかく明示的に書いているのに、
意図したジョインの形になっていないので、
上書きされちゃったら困るねというお話になりまして、
このプレリクエストでは、
例えばleftouterjoinsって書いてあるのであれば、
leftouterjoinsを優先してそのまま使いましょうと。
なので発行されるクエリは、
select posts from posts leftouterjoinsauthors on authors.id
select posts from posts leftouterjoinsauthors.id
where authors.id is not nullという形。
リフトジョインした上で、
authors.idがヌルじゃないレコードだけを絞り込むというようなクエリに変わるよということですね。
なのでこういうバグ修正が行われましたというのが2個目でした。
12:01
さて今日はちょっとだけ長いけど、3つ目いきます。
3つ目はAdd Parameter Filter Capability for Redirect Locationsというタイトルのプレリクエストです。
こちらはアクションパックに関する変更です。
Railsアプリケーションの設定項目の一つに、
Filter Parametersというものがあるのは皆さんご存知かなと思います。
こちらはRailsガイドに記載されている内容をそのまま読むと、
パスワードやクレジットカード番号などログに出力したくないパラメーターをフィルタで除外するのに用います。
また、アクティブレコードオブジェクトに対して、
インスペクトを呼び出した際にデータベースの機密性の高い値をフィルターで除外します。
そういう説明が書いてあります。
このFilter Parametersに指定したシンボルでパラメーターの名称を指定するんですよね。
例えばパスワードとか、
Emailとか、トークンとか、それぞれのアプリケーションでこの文字列のパラメーター、
この名称で付与されるパラメーターはログとかインスペクトをした時に表示されてほしくないなというものがあると思うんですよ。
機密情報的にね。
そういった文字列をFilter Parametersに指定することで、
その名称で渡されたパラメーターは大括弧大文字でフィルタードという文字列に書き換わりますという、そういう設定ですね。
これで見えてほしくない文字列がフィルターされてマスクされてありがたいなという設定なんですけども、
ただこれ1個問題があって、
Redirect URLに付与されたパラメーターはこの設定に指定している名称であっても、
例えばパスワードとか指定してあってもそのまま露出したままになっちゃってましたという問題があったんですね。
これはあんまり嬉しくないねというので、
Redirect URLに関する設定項目としてはまた別のものがすでにもともとありまして、
Filter Redirectという設定項目があります。
これもRails Guideのリンクあるので貼ってあります。
これを設定すると、このRedirect先のURLにこの設定値に含まれた文字列を含む、
15:02
あるいはこの設定に指定した正規表現にマッチする、
そういうRedirect URLだった場合に、
このRedirect URLがまるっとFilteredという文字列に書き換わる、
そういう設定になっています。
ただこれで一応ね、
ヒトック情報というか見えたくない情報はフィルターマスクされて、
それだけでも嬉しいっちゃ嬉しいんですけど、
この設定をするとRedirect URLのドメイン名とかパスとか、
全部まるっと上書きFilteredという文字列に変わってしまうと。
なので例えば別にドメインとかパスとかは別に書き換えなくてもいいんじゃと。
本当に見えてほしくないパラメーターとかだけ書き換えたいんだけどな、
みたいなことはRedirect URLに対しては設定ができないというのがこれまでの状況だったみたいです。
ただ今回のプレリクエストでその状況をどういうふうに解決するかというと、
このRedirect URLに関してもこのフィルターパラメーター図で設定した名称のパラメーターはフィルタードに書き換わるようになりましたと。
そういう実装ですね。
なのでこれは本当に純粋にありがたい。
もう何もしなくても今まで見えてたパスワードとかRedirect URLのパラメーターのパスワードとかがね、
あんまRedirect URLでパスワードとか渡すんじゃねえみたいな話はあるかもしれないんですけど、
やむを得ずそういう、あとは長いトークンとか渡すことはあるかなと思うんですけど、
その辺のトークンとかを例えばフィルターしたいというようなときに、
フィルターパラメーターにトークンって書いておいてあげれば、
Redirect URLの方のパラメーターも書き換わるようになったというので便利だねというお話ですね。
よし、じゃあこんなところで今回も3つ紹介することができました。
こんなところで第8回のTanaken on Railsは終わりにしたいと思います。
ではまた来週。バイバイ。
17:31

Comments

Scroll