大事なことは大体Rails ガイドが教えてくれる

この記事はGMOペパボ Advent Calendar 2018 - Qiita12日目の記事です。昨日は@genkiroidさんのGo と連携する Vim プラグイン | /etc/motgでした。

この数ヶ月、Railsのコードを書いていて詰まったときや疑問に思ったとき、Ruby on Rails APIRuby on Rails ガイドを読むようにしています。そのなかでも、Rails ガイドの記載が問題解決の糸口となることがあったので、今回はその小ネタを紹介します。既にご存知の方は退屈かもしれません。

railsguides.jp

モデルのバリデーションで自然数またはnilを許容する

状況

モデルの特定のケースでのみ自然数が入り、それ以外はnilとなるフィールドを作ることになりました。バリデーションとして、validates :count, numericality: { only_integer: true, greater_than_or_equal_to: 1 }と書いたのですが、このバリデーションだとcount: nilのときinvalidになってしまいます。

どこを読んだ

Active Record バリデーション | Rails ガイドを読むと

デフォルトでは、numericalityのnil値は許容されません。allow_nil: trueオプションでnil値を許可できます。

と記載されています。 validates :count, numericality: { only_integer: true, greater_than_or_equal_to: 1 }, allow_nil: trueとすることで、nilまたは自然数のときvalidとなるバリデーションを書くことができました。

メールのテストをJob specで動かすとたまにコケる

状況

メールの内容を確認するテストをRSpecのjob-specに書いていたところ、たまにテストが落ちてしまうようになりました。テストの結果を見ると期待と異なる別の種類のメールを受信したことになっていました。

どこを読んだ

Rails テスティングガイド | Rails ガイドを読むと

ここでメイラーのテスト作成方法の詳細部分についてご説明したいと思います。config/environments/test.rbのActionMailer::Base.delivery_method = :testという行で送信モードをtestに設定しています。これにより、送信したメールが実際に配信されないようにできます。そうしないと、テスト中にユーザーにスパムメールを送りつけてしまうことになります。この設定で送信したメールは、ActionMailer::Base.deliveriesという配列に追加されます。

とあります。そしてその下には

このActionMailer::Base.deliveriesという配列は、ActionMailer::TestCaseとActionDispatch::IntegrationTestでのテストを除き、自動的にはリセットされません。それらのテストの外で配列をクリアしたい場合は、ActionMailer::Base.deliveries.clearで手動リセットできます。

とも書かれています。RSpecの Job specは上記2つのクラスを使用していないので、手動でのリセットが必要なことがわかりました。

after do
  ActionMailer::Base.deliveries.clear
end

メールが絡むテストで上記のコードを挟むことにより、テストが失敗することは無くなりました。

簡単な内容ではありますが以上です。