Railsチュートリアル第7章
はじめに
Ruby on Railsチュートリアル(第6版)のメモ、演習の解答例を記述した記事です。
解答は個人のものなので、誤りがあればご指摘ください。
開発環境 Ruby: 2.7.2 , Rails: 6.1.4
メモ
debugger
byebug gemのdebuggerメソッドをコード内に埋め込むことで埋め込んだ箇所の状況を調べることができる。
調べたあとはコード内からdebuggerを取り除く必要がある。
ヘルパー
form_with
form_withヘルパーはAcrive Recordのオブジェクトを取り込み、取り込んだオブジェクトの属性を使ってフォームを構築する。
参考:form_with | Railsドキュメント
content_tag
HTMLとERBが混ざっているときに置き換えるとコードが簡潔になる。
7.4.4の演習2を参照
参考:
content_tag | Railsドキュメント
ストロングパラメータ
マスアサインメントの脆弱性を対策するためのもの。
必須のパラメータと許可されたパラメータを指定して受け取ることができる。
こうすることで意図的にパラメータを書き換えられることを防ぐ
params.require(:user).permit(:name, :email, :password, :password_confirmation)
必須の属性を:userとし、名前、メールアドレス、パスワード、パスワードの確認を許可している。それ以外のパラメータはエラーとして弾くようになっている。
演習
7.3.4
演習1
リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。
POSTリクエストを送信した際のエラーメッセージを追加
test "invalid signup information" do get signup_path assert_no_difference "User.count" do post users_path, params: { user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } } end assert_template 'users/new' assert_select 'div#error_explanation' assert_select 'div.field_with_errors' assert_select 'li', "Name can't be blank" assert_select 'li', "Email is invalid" assert_select 'li', "Password confirmation doesn't match Password" assert_select 'li', "Password is too short (minimum is 6 characters)" end
7.4.4
演習1
7.4.2で実装したflashに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.32に最小限のテンプレートを用意しておいたので、参考にしてください(FILL_INの部分を適切なコードに置き換えると完成します)。ちなみに、テキストに対するテストは壊れやすいです。文量の少ないflashのキーであっても、それは同じです。筆者の場合、flashが空でないかをテストするだけの場合が多いです。
test "valid signup information" do get signup_path assert_difference "User.count", 1 do post users_path, params: { user: { name: "Example User", email: "user@example.com", password: "password", password_confirmation: "password" }} end follow_redirect! assert_template 'users/show' assert_not flash.empty? end
演習2
本文中でも指摘しましたが、flash用のHTML(リスト 7.29)は読みにくいです。より読みやすくしたリスト 7.33のコードに変更してみましょう。変更が終わったらテストスイートを実行し、正常に動作することを確認してください。なお、このコードでは、Railsのcontent_tagというヘルパーを使っています。
<div class="alert alert-<%= message_type %>"><%= message %></div>
HTMLとERBが混在しているコードをcontent_tagで置き換えると
<%= content_tag(:div, message, class: "alert alert-#{message_type}")%>
演習3
リスト 7.26のリダイレクトの行をコメントアウトすると、テストが失敗することを確認してみましょう。
# redirect_to user_url @user
テストの結果
yuy@yu sample_app % rails test Running via Spring preloader in process 45196 Started with run options --seed 2921 ERROR["test_valid_signup_information", #<Minitest::Reporters::Suite:0x0000000114b9c728 @name="UsersSignupTest">, 0.32726700004423037] test_valid_signup_information#UsersSignupTest (0.33s) RuntimeError: RuntimeError: not a redirect! 204 No Content test/integration/users_signup_test.rb:24:in `block in <class:UsersSignupTest>' 20/20: [=============================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.42140s 20 tests, 47 assertions, 0 failures, 1 errors, 0 skips
演習4
リスト 7.26で、@user.saveの部分をfalseに置き換えたとしましょう(バグを埋め込んでしまったと仮定してください)。このとき、assert_differenceのテストではどのようにしてこのバグを検知するでしょうか? テストコードを追って考えてみてください
def create @user = User.new(user_params) if false flash[:success] = "Welcome to the Sample App!" redirect_to user_url @user else render 'new' end end
POSTリクエストを送信したあとのデータベースの変化についてエラーが出ている。
yuy@yu sample_app % rails test Running via Spring preloader in process 46971 Started with run options --seed 47383 FAIL["test_invalid_signup_information", #<Minitest::Reporters::Suite:0x000000011fc5b988 @name="UsersSignupTest">, 0.45664799999212846] test_invalid_signup_information#UsersSignupTest (0.46s) Expected at least 1 element matching "div#error_explanation", found 0.. Expected 0 to be >= 1. test/integration/users_signup_test.rb:11:in `block in <class:UsersSignupTest>' FAIL["test_valid_signup_information", #<Minitest::Reporters::Suite:0x000000011fc50cb8 @name="UsersSignupTest">, 0.4575549999717623] test_valid_signup_information#UsersSignupTest (0.46s) "User.count" didn't change by 1. Expected: 1 Actual: 0 test/integration/users_signup_test.rb:21:in `block in <class:UsersSignupTest>' 20/20: [=============================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.51240s 20 tests, 42 assertions, 2 failures, 0 errors, 0 skips
おわりに
本章の終わりに本番環境の設定をしましたが、そこではセキュリティ面とユーザーが利用しやすい環境を作ることが大切だということが窺えました。
引き続き次の章もがんばります!!