form_withの:scopeオプション
いつも当たり前のようにお世話になっているform_withなのですが、時々登場する:scopeって何なんだろうとずっと気になりつつもスルーしていたので、ちょっと考えてみました。
form_withの書き方
まずはform_withの書き方。モデルのインスタンスを与える場合とURLを指定する場合があります。
<%= form_with model: @post, local: true do |f| %> <%= f.label :title, "title" %> <%= f.text_field :title %> <%= f.submit "submit" %> <% end %>
<%= form_with url: posts_path, local: true do |f| %> <%= f.label :title, "title" %> <%= f.text_field :title %> <%= f.submit "submit" %> <% end %>
送った値をデータベースに保存するときはモデルのインスタンスを与え、保存する必要がないときはURLの指定でいい、というように習った気がします。
scopeの使い方
:scopeは各inputのname属性をグループ化するのに使います。
以下の例の、for、name、idあたりに注目してみてください。
まずはscopeなしのフォームです。
<%= form_with url: posts_path, local: true do |f| %> <%= f.label :title, "title" %> <%= f.text_field :title %> <%= f.submit "submit" %> <% end %>
これから生成されるHTMLは次のようになります。
<form action="/posts" accept-charset="UTF-8" method="post"> <input type="hidden" name="authenticity_token" value="lZncvnvoVbrMXAFZh+OKMm0tffHWRpHobLG8u8rfbyGV0IvY0+bReGM7s4gsx6g7EhDHQyJGnqAKYcFR0qNv9w=="> <label for="title">title</label> <input type="text" name="title" id="title"> <input type="submit" name="commit" value="submit" data-disable-with="submit"> </form>
これにscopeを加えます。
<%= form_with url: posts_path, scope: :post, local: true do |f| %> <%= f.label :title, "title" %> <%= f.text_field :title %> <%= f.submit "submit" %> <% end %>
生成されるHTMLはこうなります。
<form action="/posts" accept-charset="UTF-8" method="post"> <input type="hidden" name="authenticity_token" value="6tBiAMKg7985ctmGN7VNykTOPyt0XQv9mngAmaIcjjLqmTVmaq5rHZYVa1eckW/DO/OFmYBdBLX8qH1zumCO5A=="> <label for="post_title">title</label> <input type="text" name="post[title]" id="post_title"> <input type="submit" name="commit" value="submit" data-disable-with="submit"> </form>
labelのfor属性、inputのid属性がtitleからpost_titleに変わり、name属性がtitleからpost[title]に変わりました。
これにより、リクエストにのせて送られるパラメーターの構造が変わります。
scopeを設定していない場合はparams[:title]でtitleを取得でき、scope: postを設定した場合はparams[:post][:title]でtitleを取得できます。
paramsの中のpostというハッシュの中のtitle、という感じですね。
ちなみにモデルのインスタンスを与えた場合は、scopeを設定しなくても初めからグループ化されています。
まとめ
- form_withの書き方はモデルを指定する方法とURLを指定する方法の二通り
- scopeを設定することで、フォームの各要素のname属性をグループ化できる
- パラメーターの階層が一つ深くなる