Railsのform_withの使い方

Railsform_with メソッドへの理解が曖昧だったので簡単にまとめました。

form_with の特徴

  • Rails5.1以降はform_tagform_for が非推奨になり、替わりにform_with が推奨になる
  • form_for 的な使い方、form_tag 的な使い方の2つの使い方ができる
  • オプションの() は省略可能
  • デフォルトのHTTPメソッドはPOST(他のHTTPメソッドも指定する可能)
  • remote: true がデフォルト(Ajaxでの非同期通信)

form_withまとめ | Rails Ambassador ~Railsの伝道師~

2つの使い方

from_withform_tag 的な使い方、form_for 的な使い方の2つの使い方ができる

  • form_tag 的な使い方: 関連モデル無し
  • form_for 的な使い方: 関連モデル有り

関連モデル無し(form_tag的)

指定したURLに対してパラメータを送信するフォームを作成する(DBにデータを保存しない)。

  • HTTPメソッドはPOST(デフォルト)
  • 送信したいURLはurl: で指定する
  • 送信されたパラメータはparams[:email] のような形で取得できる
# form_tagを使った書き方

<%= form_tag users_path do %>
  <%= text_field_tag :email %>
  <%= submit_tag %>
<% end %>
# form_withで書き換え

<%= form_with(url: users_path) do |f| %>
  <%= f.text_field :email %>
  <%= f.submit %>
<% end %>

関連モデル有り(form_for的)

指定したモデルオブジェクトを元にフォームを作成する(DBに関連した処理を行う)。

# form_forを使った書き方

<%= form_for @user do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>
# form_withで書き換え

<%= form_with(model: @user) do |f| %>
  <%= f.text_field :email %>
  <%= f.submit %>
<% end %>

指定したモデルオブジェクトのレコードの状態によって対応するコントローラーのアクション(create、update)を自動で切り替えてくれます。

Action View フォームヘルパー - Railsガイド

下記のルーティングが設定されている場合は次のような動作になります。

$ rails routes
         POST   /users(.:format)      users#create
         PATCH  /users/:id(.:format)  users#update
         PUT    /users/:id(.:format)  users#update
         DELETE /users/:id(.:format)  users#destroy
    user GET    /users/:id(.:format)  users#show
   users GET    /users(.:format)      users#index
new_user GET    /users/new(.:format)  users#new

パターン1: 指定したモデルオブジェクトが空の場合

下記のような新たに作成されたモデルオブジェクトを元にフォームを作成した場合はcreateアクション用のフォームが生成されます。

# app/controllers/users_controller.rb

def new
  @user = User.new
end
# app/views/users/new.html.erb

<%= form_with(model: @user) do |f| %>
  <%= f.text_field :email %>
  <%= f.submit %>
<% end %>
# 生成されるHTML

<form action="/users" method="post">
  ...
</form>
  • 送信されるURL: /users
  • HTTPメソッド: POST
  • 実行されるアクション: users#create

パターン2: 指定したモデルオブジェクトが存在している場合

下記のように既存のモデルオブジェクトを元にフォームを作成した場合はupdateアクション用のフォームが生成されます。

# app/controllers/users_controller.rb

def edit
  @user = User.find(params[:id])
end
# app/views/users/edit.html.erb

<%= form_with(model: @user) do |f| %>
  <%= f.text_field :email %>
  <%= f.submit %>
<% end %>
# 生成されるHTML

<form action="/users/update対象のid" method="post">
  <input type="hidden" name="_method" value="patch">
  ...
</form>
  • 送信されるURL: /users/update対象のid
  • HTTPメソッド: PATCH
  • 実行されるアクション: users#update
  • type=hidden で隠しinput要素が追加で生成され、value="patch" でデフォルトのHTTPメソッドのPOSTががPATCHに変更される

Action View フォームヘルパー - Railsガイド

まとめ

曖昧だったform_with の使い方が理解できたのでスッキリした。 フォーム周りは複雑なのでガンガン触って覚えていきたい。

参照

form_withまとめ | Rails Ambassador ~Railsの伝道師~

Action View フォームヘルパー - Railsガイド

【Rails】 form_withの使い方を徹底解説! | Pikawaka