form_withのlocal: trueって必要なん？これ何なん？（Ruby on Rails）

# はじめに：私が犯した罪と償い
社内研修の一環で、プチIoTシステムを開発しています。
そんな中、自分のエラーの解消に大先輩3人の60分を溶かしてしまったので、せめてもの償いのために、学んだことをメモしておきます。

おかげで、

1. <strong>Railsのメソッド`form_with`の引数`local: true`が何の役に立っているのか</strong>
2. <strong>アプリ作成時のネットワーク通信のこと</strong>

が痛いほどわかりました。

環境
Rails6.0.3, macOS Catalina 10.15.7

# 何のエラー出してたん？
supplierモデルに対する、新規登録（new/create）のフォームで、バリデーションが通らなかった時にエラーメッセージをビューで表示したい！
ただそれだけのことでした。しかし仕込んだそのエラーメッセージが表示されません！

うまくいっていなかったビューはこちら。１行目にご注目。

```erb:new.html.erb
<%= form_with model: @supplier do |form| %>

  <% if form.object.errors.any? %>
    <div id="error_explanation">
      <div class="alert alert-danger">
        エラーが <%= form.object.errors.count %> 個あります。 
      </div>
      <ul>
      <% form.object.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="mb-3">
    <%= form.label :会社名, for: 'company', class: 'col-sm-2 col-form-label' %>
    <%= form.text_field :name, class: 'form-control', id: 'company', placeholder: '株式会社 喧嘩上等' %>
  </div>
  <div class="mb-3">
    <%= form.label :メールアドレス, for: 'email', class: 'col-sm-2 col-form-label' %>
    <%= form.text_field :email, class: 'form-control', id: 'email', placeholder: 'order@example.com' %>
    </div>

  <%= form.submit '送信', class: 'btn' %>
<% end %>
```

私は、Railsチュートリアル出身なのですが、そこでは`form_with`に`local: true`という引数を渡していました。しかし、ネットでform_withの使い方を他で改めて調べてみたところ、この引数がなくても新規レコードの登録処理ができそうだったので、省いてみちゃえ！と出来心が全ての事の始まりでした。実際、これでデータベースまでの登録はきちんとできていて、なんだlocalパラメータいらないんじゃん。となっていました。

一方.....`if form.object.errors.any?`を入れても、エラー表示は一切できませんでした。

ちなみにコントローラはこんな感じ。問題なさそう。

```ruby:supplier.controller.rb
class SuppliersController < ApplicationController

  def new
    @supplier = Supplier.new
  end

  def create
    @supplier = Supplier.new(supplier_params)
    if @supplier.save
      redirect_to suppliers_path
    else
      render 'new'
    end   
  end

end
```

`binding.irb`をビューやコントローラなど至る箇所に埋め込んでは、各変数に値が入っているかどうかをチェック。
`form.object`には値もある。`@supplier`にしても同じ。`errors.any?`もtrueを返している。何故なんだ。タイポもなさそう。先輩たちの時間をどんどん溶かしてしまっています...。

# 解決：「クルクルしてない！」
「**クルクルしてない！**」
問題の原因が全くわからず途方にくれていた末に、ある先輩が上記のセリフを発せられました。
フォームの送信ボタンを教えても画面がリロードしないことを変に思ったようで、そこからフォームの動きが怪しいとなりました。そこで`local: true`を追記したのです。

```erb:new.html.erb
<%= form_with(model: @supplier, local: true) do |form| %>

以下略
```

# 学び１：`local: true`とは？
form_withはRailsの比較的新しいメソッド。このメソッドではデフォルトがAjax通信で、非同期通信になってしまうのです。（これはRails 5.1〜6.0の仕様でRails 6.1からは同期通信がデフォルトに戻っているそうです。当記事はRails6.0.3です。→[参考](https://api.rubyonrails.org/v6.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with)。@jnchito さん、ありがとうございます！）それはつまり、必要な箇所だけページが更新され、その他の箇所はそのままになるという事。だからエラーメッセージのHTML部分が加えられなかったのです。
ここに`local: true`と引数を渡す事で、これが通常のHTTPリクエストになり、ページ全体が返ってきてページがリロードされ、エラーメッセージも表示されるようになります。

# 学び２：アプリの開発でネットワークをチェックする
その後、ブラウザの開発者ツールでネットワークを確認しました。
![スクリーンショット 2021-02-25 15.06.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/9c10100c-71a8-0490-8fcc-5107e4a11ced.png)
↑Typeがxhrになっとる。xhr=XMLHttpRequest。Ajaxのxの部分。つまりAjax通信になっているということ。

![スクリーンショット 2021-02-25 15.06.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/b69ab9d8-5387-c5df-2f67-9400700fd7ff.png)
↑suppliersが下の方に来ています。これはつまり、他の要素がリロードされずにそのまま残っているということ。

↓一方、`local: true`にしておく（＝通常のHTTP通信にする）と、下のようなネットワーク動作になります。
suppliersがリストの一番先頭にいるのが分かるかと思います。
これは、ページ内の全ての要素が更新され、suppliersが一番最初に処理されたという事です。
![スクリーンショット 2021-02-25 15.08.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/3e19188b-e663-fb3a-5f0e-b677aa042ca3.png)

「<strong>エンジニア中級者になるには、ネットワークのことを理解すること</strong>」と先輩。

# 最後に
エラーの解消の過程で、他にもbinding.irbの使い方、errorsやfull_messagesにどんなデータが格納されているのかなどいろんなことを勉強できました。

先輩方ありがとうございました！

@yuuu 
@yukabeoka 
@Junkins 

宣伝ではないですが、周りがこんなエラーに親身に向き合ってくれる先輩ばかりです。
本当にFusicという会社でエンジニアキャリアを始められて幸せすぎる...。