技術ブログ

(技術系中心)基本自分用備忘録なので、あくまで参考程度でお願いします。

Railsのform_withのあれこれ【殴り描き】

form_withのあれこれ

Rails5.1以降に登場したform_withの利用方法のメモ残す。 Rails5.1以前に利用されていたform_forform_tagは非推奨になったので基本利用しないようにしましょう。

form_withではモデルに関連するもの、関連づかないフォームのどちらでも利用可能になります。 (以前はモデルに関連するものをform_for、関連づかないフォームをform_tagと使い分けていた)

モデルに関連するときの書き方

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

form_with引数のインスタンス(@user)が何も情報を持っていない場合、createアクションへ、 情報を持っている場合、updateアクションへ自動的に振り分けてくれます。

例えば、newの場合は自動でcreateアクションに振り分けられる。 既に情報を持っているcreateの場合は自動でupdateアクションに振り分けられる。

モデルに関連づかない時の書き方

<%= form_with url: users_path do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

モデルに紐づかない場合はurlを明示的に記載する。

form_withの利用方法

form_with(model: nil, scope: nil, url: nil, format: nil, **options)

form_withで利用できるオプション

form_withではたくさんのオプションが利用できます。 以下のRails 5.1〜: ‘form_with’ APIドキュメント完全翻訳に詳細説明が記載されています。 ↓ https://techracho.bpsinc.jp/hachi8833/2017_05_01/39502

form_withの中でvalidationエラーを表示させるにはlocal_trueオプションが必須

form_withの中で以下のようにvalidationエラーを表示させようとしたのですが、何故か画面に表示されないケースがありました。

このコードはslimテンプレート利用してます、erbとslim混合して読みにくくてすいません。

...前略...

= form_with model: @hoge do |f| 
  / createに失敗するとエラー表示
  - if @hoge.errors.any?
    .alert.alert-warning
      ul
      - @hoge.errors.full_messages.each do |message|
        li = message

最初はif @hoge.errors.any?が作動してないのかな?と思ったのですが調べてみるとif分は正常に作動していました。

で、詳しく調べてみた結果オプションでlocal: trueを指定してないのが原因でした。 ですので、以下のような書き方が正解です。

= form_with model: @hoge, local: true do |f| 

何故local_trueオプションが必須?

form_withでは何も指定しない場合デフォルトでremote: trueになるようです。 remote: trueではXMLHTTPRequestオブジェクトリクエストを自動で送信するので、無効化する為にlocal: trueを指定してあげます。

<%= form_with url: posts_path do |form| %>
  <%= form.text_field :title %>
<% end %>

html変換 ↓

<form action="/posts" method="post" data-remote="true"> 
  <input type="text" name="title">
</form>

確かに自動でdata-remote="trueになっていますね。

参考サイト

https://api.rubyonrails.org/v6.0/classes/ActionView/Helpers/FormHelper.html#method-i-form_with

https://qiita.com/k_senbei/items/a361171f653edcd888ad