LoginSignup
19
11

More than 1 year has passed since last update.

【Rails勉強ネタ】 HTMLのformは本当にGETとPOSTに制限されている??

Last updated at Posted at 2019-04-13

きっかけ

書籍のwebを支える技術を読んでいたら、p98に以下の記述がありました。

しかし、現実に一番よく利用されているのはGETとPOSTの2つです。
これはHTMLのフォームで指定できるメソッドがGETとPOSTだけという制限に起因します。

これを読んで、「だとすると、updateアクション(PATCHメソッド)はどうやって実現されるのだろう??」
と思ったのですが、すぐ隣のページに書かれてました。
どうやらRailsは_method パラメーターを使って実現させているみたいです。

実際に確認してみる

お知らせを投稿できるNoticeというModelがあるとします。

ルーティング

(当たり前ですが)updateアクションはPATCHPUTで発動となっています。

$ rails routes|grep notice
     notices GET      /notices(.:format)                                                                  notices#index
             POST     /notices(.:format)                                                                  notices#create
  new_notice GET      /notices/new(.:format)                                                              notices#new
 edit_notice GET      /notices/:id/edit(.:format)                                                         notices#edit
      notice PATCH    /notices/:id(.:format)                                                              notices#update
             PUT      /notices/:id(.:format)                                                              notices#update
             DELETE   /notices/:id(.:format)                                                              notices#destroy

HTML

editページのformを右クリック→ページのソースを表示で見てみます。

<form class="edit_notice" id="edit_notice_18" action="/notices/18" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" />
  <input type="hidden" name="_method" value="patch" /><input type="hidden" name="authenticity_token" value="lGc0ypr/fV1WxhHZm6OS1ehZMpPj9IIgKF/8S5pm3FglyNHWxFgGLGt25AjoFb9BAINs4iRwg7VXn8eLjv9QGQ==" />
  <label>お知らせ</label>
  <textarea name="notice[body]" id="notice_body">test</textarea>
  <input type="submit" name="commit" value="登録" data-disable-with="登録中…" />
</form>

確かにformタグを見ると、 method="put" や method="patch"ではなく、 method="post" となっています。
そして、隠しパラメータ(hidden)に_methodパラメータを用意しているのが確認できます。↓
<input type="hidden" name="_method" value="patch" />

Wiresharkでパケットキャプチャーして見た

リアルなhttpパケットが見たいのでキャプってみました。
wiresharkでインターフェイスをlocalhostに指定してあげると、localhost:3000とのパケット通信をキャプチャーできます。

画像はeditページでsubmitした時のhttpパケットです。
スクリーンショット 2019-04-13 11.51.46.png

確かにPOST メソッドのHTTPリクエストが送信されていることが確認できます。

また、HTML Form URL Encoded: application/x-www-form-urlencoded 内で
Form item: "_method" = "patch"というパラメーターが確認できる。
おそらくこのパラメーターを見て"patch"メソッドが送られたこととして処理しているんだと思われる(本当はPOSTメソッドを受け取っているが)。

デバッグ

updateアクション内にbinding.pryを仕込んでデバッグ。

[1] pry(#<NoticesController>)> request
=> #<ActionDispatch::Request:0x00007fd6cb6156d0
 @env=
  {"CONTENT_LENGTH"=>"210",
   "CONTENT_TYPE"=>"application/x-www-form-urlencoded",
   "GATEWAY_INTERFACE"=>"CGI/1.1",
   "PATH_INFO"=>"/notices/15",
   "QUERY_STRING"=>"",
   "REMOTE_ADDR"=>"::1",
   "REMOTE_HOST"=>"::1",
   "REQUEST_METHOD"=>"PATCH",
   "REQUEST_URI"=>"http://localhost:3000/notices/15",
   "SCRIPT_NAME"=>"",
   "SERVER_NAME"=>"localhost",
   "SERVER_PORT"=>"3000",

実際に送信したHTTPリクエストはPOSTメソッドでしたが、Rails上ではPATCHメソッドを受け取ったと認識して処理しているようです。
("REQUEST_METHOD"=>"PATCH")

疑問に思ったこと

今回の確認では_methodでpatchが当てがわれているが、putはどのような条件で出てくるのだろう??
(何かの条件でputのパターン、patchのパターンがあるのだろうか)

19
11
2

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
19
11