はじめに
本記事は、プログラミングの学習を始めて1ヶ月の初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。
今回の疑問点
今回の疑問点は、
form_with
はどのようにしてPOST
とPATCH
を判断しているのか
です。
非同期通信によるコメント機能を実装していた際に疑問を抱きました。
納得のいく結論に至るまでかなり時間を要したのでまとめておきます。
疑問点についての解説
###結論
モデルのインスタンスに対するpersisted?
の戻り値がtrueをならPATCH
、そうでなければPOST
。つまり、データベースにインスタンスが保存されているかで判断している。
###persisted?
とは
persisted?
メソッドは、インスタンスがデータベースに保存済みかどうかをチェックするメソッドです。インスタンスがデータベースに保存されていればtrue、保存されていなければfalseを返します。
###検証
def destroy
@book = Book.find(params[:book_id])
@book_comment = @book.book_comments.find(params[:id])
p @book_comment.persisted?
@book_comment.destroy
p @book_comment.persisted?
p @book_comment
render 'books/show'
end
まず、コメントを削除するためのdestroyアクションを上記のように記述し、「削除」ボタンをクリックするとターミナルには以下のように出力されます。
↳ app/controllers/book_comments_controller.rb:17
BookComment Load (0.1ms) SELECT "book_comments".* FROM "book_comments" WHERE "book_comments"."book_id" = ? AND "book_comments"."id" = ? LIMIT ? [["book_id", 1], ["id", 148], ["LIMIT", 1]]
↳ app/controllers/book_comments_controller.rb:18
true
(0.1ms) begin transaction
↳ app/controllers/book_comments_controller.rb:20
BookComment Destroy (4.0ms) DELETE FROM "book_comments" WHERE "book_comments"."id" = ? [["id", 148]]
↳ app/controllers/book_comments_controller.rb:20
(5.1ms) commit transaction
↳ app/controllers/book_comments_controller.rb:20
false
#<BookComment id: 148, user_id: 9, book_id: 1, comment: "テスト", created_at: "2021-12-08 17:46:14", updated_at: "2021-12-08 17:46:14">
Rendering book_comments/destroy.js.erb
(一部省略)
(renderされた画面で新規投稿)
Started POST "/books/1/book_comments"
注目していただきたいのが、
true
BookComment Destroy (4.0ms) DELETE FROM "book_comments" WHERE "book_comments"."id" = ? [["id", 148]]
false
#<Book id: 1, title: "gragrea", body: "gerageag", user_id: 1, created_at: "2021-12-02 07:52:27", updated_at: "2021-12-02 07:52:27">
#<BookComment id: 148, user_id: 9, book_id: 1, comment: "テスト", created_at: "2021-12-08 17:46:14", updated_at: "2021-12-08 17:46:14">
Started POST "/books/1/book_comments"
です。
まず、
true
BookComment Destroy (4.0ms) DELETE FROM "book_comments" WHERE "book_comments"."id" = ? [["id", 148]]
false
の3文については、前後関係に注目してください。
@book_comment.destroy
の前にあるp @book_comment.persisted?
の戻り値はtrue
ですが、
@book_comment.destroy
の後に記述したp @book_comment.persisted?
の戻り値はfalse
です。
このとこから、①destroyメソッドによってデータベースからレコードが削除されたことがわかります。
※②@book_comment.destroy
をコメントアウトするとデータベースからレコードが削除されないため、コメントが削除されず、かつ、renderされた画面で新規投稿をするとHTTPメソッドはPATCHとなります。
次に、
#<BookComment id: 148, user_id: 9, book_id: 1, comment: "テスト", created_at: "2021-12-08 17:46:14", updated_at: "2021-12-08 17:46:14">
です。
上記の2文からは。③destroyメソッドが実行された後も@book_comment
は値を持ち続けていることがわかります。
※値が残っているため、renderされた画面に投稿フォームとコメント一覧がありますが、投稿フォームに削除したコメントの内容が初期値として入力されます。
最後に
Started POST "/books/1/book_comments"
からは、④再度新規投稿を行うとHTTPメソッドはPOST
となっていることがわかります。
⑤book_comments_controller.rb
ではモデルのインスタンスに対して実行しているのはnewメソッドではなく、findメソッドです。
###検証からわかること
①〜④から、form_withのHTTPメソッドの判断基準は、
form_withに渡すインスタンスが値を持っているか否かではなく(③、④)、また、モデルのインスタンスに対して実行しているメソッドがnewメソッドかfindメソッドかでもなく(⑤)、モデルのインスタンスがデータベースに保存されているか否かである(①、②)
ことがわかります。
まとめ
判断基準について、モデルのインスタンスに対してnewメソッドが実行されていればPOST
、findメソッドが実行されていればPATCH
と説明されていたり、form_withに渡すインスタンスが値を持っていれば、PATCH
、空のインスタンスであれば、POST
と説明されたりしていますが、上述の通り、
データベースにインスタンスが保存されているか否かで判断
していることがわかりました。