18
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】form_with と params って結局なんやねん

18
Posted at

はじめに

こんにちは!hinata です!

Railsで開発していると、こんな経験ありませんか?

  • フォームは作れたのに、params が想定と違う形で届く
  • params[:user][:name] だと思ったら nil になる
  • form_withmodel / url / scope の違いがよく分からない
  • そもそも paramsって何者? という気持ちになる

正直に言うと、自分は form_with と params の理解がかなり曖昧でした。

そこでこの記事では、

  • params はそもそもどこから来るのか
  • どんなルールで送られてくるのか
  • form_with の指定によって params がどう変わるのか

を、具体的なコード例ベースで整理します。

⚠️ 注意

本記事の内容は、Rails初学者である筆者が
実際に開発中につまずいたポイントと、その時点での理解をもとにまとめたものです。

設計や実装については、より良い書き方・考え方が存在する可能性がありますが、
「初学者がどう悩み、どう整理したか」という観点で読んでいただけると嬉しいです。

そもそも params とは何か?

params は、ブラウザからサーバーに送られてきたデータをまとめたものです。

Railsでは、以下の情報がすべて params に入っています。

  • フォームで入力された値
  • URLのクエリパラメータ(?q=rails など)
  • ルーティングで指定された :id

例:URLに含まれる params

/users/10?active=true
params
# {
#   "id" => "10",
#   "active" => "true"
# }

👉 params の中身はすべて文字列(String)

フォームから送られるデータの正体

HTMLフォームでは、すべての入力値は次の形で送信されます。

name=value

Railsは、この name をもとに params を組み立てています。

name と params の対応関係

フラットな例

<input name="q" value="rails">
params[:q]
# => "rails"

ネストする例(角括弧)

<input name="user[name]" value="太郎">
params[:user][:name]
# => "太郎"

さらにネストする例

<input name="search[conditions][keyword]" value="rails">
params
# {
#   "search" => {
#     "conditions" => {
#       "keyword" => "rails"
#     }
#   }
# }
params[:search][:conditions][:keyword]
# => "rails"

👉 角括弧 [] が Hash のネスト構造になる

ここまでが Rails以前の前提知識 です。

form_with は何をしているのか?

ここでようやく Rails の話に戻ります。

form_with は、params を直接操作していません。
やっていることはシンプルで、

input の name を Rails流に自動生成しているだけ

です。

つまり、

  • model を渡す
  • scope を指定する
  • 何も指定しない

これらの違いはすべて
**「どんな name を生成するか」**の違いです。

form_with × params パターン集

ここからは、name がどう作られ、params がどうなるかだけに注目します。

パターンA:model を渡す(CRUDで最頻出)

<%= form_with model: @user do |f| %>
  <%= f.text_field :name %>
<% end %>

生成される name:

user[name]

params:

params[:user][:name]

👉 model名がそのまま params のキーになる


パターンB:url のみ(scopeなし)

<%= form_with url: search_users_path, method: :get do |f| %>
  <%= f.text_field :q %>
<% end %>

生成される name:

q

params:

params[:q]

👉 f を使っていても、scope がなければネストされない


パターンC:scope を指定する

<%= form_with url: search_users_path, method: :get, scope: :search do |f| %>
  <%= f.text_field :q %>
<% end %>

生成される name:

search[q]

params:

params[:search][:q]

👉 scope は params のルートキーを作る


パターンD:scope を user にする

<%= form_with url: users_path, scope: :user do |f| %>
  <%= f.text_field :name %>
<% end %>

params:

params[:user][:name]

👉 model がなくても、modelっぽい params を作れる


パターンE:text_field_tag で name を直指定する

<%= form_with url: search_users_path, method: :get do %>
  <%= text_field_tag "user[name]" %>
  <%= submit_tag "検索" %>
<% end %>

params:

params[:user][:name]

👉 params を完全にコントロールしたいときの最終手段

チートシート(ここだけ見ればOK)

form_with input params
model: @user f.text_field :name params[:user][:name]
url: f.text_field :q params[:q]
url + scope: :search f.text_field :q params[:search][:q]
なんでも text_field_tag "user[name]" params[:user][:name]

よくある勘違い

method: :get は params が違う?

違いません。
URLに表示されるだけで、controller では同じ params です。

Turbo が原因?

params の形自体は変わりません。

Strong Parameters のせい?

→ それは「取り出し方」の話で、
params がどう作られるかとは別の話です。

まとめ

  • params は ブラウザから送られてきたデータの集合
  • params の形は input の name で決まる
  • form_with は name を自動生成してくれるだけ
  • 迷ったら HTMLを見て name を確認する

form_with の挙動が分かると、
検索フォームや複雑な条件フォームも一気に書きやすくなります。

同じところで詰まっている人の助けになれば嬉しいです 🙌

開発したアプリ「FES READY」でもたくさん今回の記事の技術を使用しているので、
よければ触ってみてください!


fesready_ogp.png

🔗 FES READY

18
7
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
18
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?