0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】form_withのHTTPメソッドの判断基準について【POSTかPATCHか】

Posted at

はじめに

 本記事は、プログラミングの学習を始めて1ヶ月の初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
 そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
 間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

今回の疑問点

 今回の疑問点は、

  form_withはどのようにしてPOSTPATCHを判断しているのか
 
 です。 

 非同期通信によるコメント機能を実装していた際に疑問を抱きました。
 納得のいく結論に至るまでかなり時間を要したのでまとめておきます。

疑問点についての解説

###結論
 モデルのインスタンスに対するpersisted?の戻り値がtrueをならPATCH、そうでなければPOST。つまり、データベースにインスタンスが保存されているかで判断している。

###persisted?とは
persisted?メソッドは、インスタンスがデータベースに保存済みかどうかをチェックするメソッドです。インスタンスがデータベースに保存されていればtrue、保存されていなければfalseを返します。

###検証

book_comments_controller.rb

  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と説明されたりしていますが、上述の通り、

データベースにインスタンスが保存されているか否かで判断

していることがわかりました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?