Railsのform_withを自分なりにまとめてみた

## はじめに
未経験からプログラミング学習中のkekiと申します。

Railsのログインの仕組みを理解する中で、`form_with` の機能と個人的に難しかった疑問二点を記事にしてみました。
ログイン付近を学習中の方や、その復習をしたい方向けの内容です。
修正・追記あれば随時更新していきます。

## form_withとは
**Railsで情報を送信するためのヘルパーメソッド**です。
`form_with`を使うことにより、簡単に入力フォームに必要なHTMLを作成することができます。
かつての`form_tag`や`form_for`メソッドをひとまとめにした大変便利なものです。
以下のような初期設定があります。

- HTTPメソッドの`POST`と`PATCH`を自動的に切り替えてくれる
- デフォルトではid属性やclass属性は付与されない
- デフォルトで`remote: true`が付与
- 関連モデルがある場合はモデルを指定し、ない場合はURLを指定する

## 主な機能
大きく6つにまとめました。
1. **自動的に送信先のアクションをcreateかupdateに振り分けてくれる**
    おそらく最も恩恵を受けている機能です（[参考記事はこちら](https://qiita.com/okonomi/items/6c2b31427161090c173a)）。
    HTTPメソッドを個別に指定することもできます。
    <br>    
2. **スコープを指定することができる**
    例えばusersコントローラとは別にsessionsコントローラを作り、ログイン画面でユーザーの情報を取得する際は以下のようなスコープの設定になります。
（詳細は下述します）
    
    ```ruby
    <%= form_with scope: :session, url: sessions_path do |f| %>
      <%= f.text_field :name %>
      <%= f.submit %>
    <% end %>
    ```
    <br>
    
3. form_withには**モデル属性にない入力フォームを追加**できる
    
    ```ruby
    <%= form_with model: @user, url: users_path do |f| %>
      <%= f.text_field :name %>
      <%= f.text_field :hoge%>
      <%= f.submit %>
    <% end %>
    ```
    <br>
4. デフォルトで`remote: true`設定（Ajaxでのリクエストがオン）になっている
    →リモート無効のフォームにしたい時は`local: true` に変更する
    (詳細は下述します)
    <br>
    
5. `form_with`にはHTMLのclassやidを設定することができる(あまり使わないかも)
    
    ```ruby
    <%= form_with model: @user, id: :任意のID, class: :任意のclass do |form| %>
      <%# フォームの部品 %>
    <% end %>
    ```
    <br>
    
6. その他formタグで様々なオプションをつけることができる
    - `form.html`でhtmlタグをつけると投稿の種類が変わる
    - `form.hidden_field`は非表示のフォームを作成し、ユーザーのidなどユーザーがフォームから入力しない情報をパラメータとして渡したいときに使える
    - `form.submit`は送信ボタンを作成する


## 自分の疑問点
```ruby
<%= form_with(scope: :session, url: sessions_path, local: true) do |f| %>
```

- **local: trueって何してるの？**
    
    これはAjax(エージャックス)処理のオフを指しています。

    Ajaxとは「JavaScriptでサーバー側との通信を非同期で行い、通信結果によって動的にページの一部だけ書き換える手法のこと」です。`form_with`はデフォルトでAjax処理が行われる設定なので、これを無効にする際には`local: true`が必要になります）

    `local: true`を使ってる理由に関しては、以下の記事が詳しいのでぜひ参考にしてみてください！
[form_withのlocal: trueって必要なん？これ何なん？（Ruby on Rails）](https://qiita.com/kakudaisuke/items/e032c7705db00e8081dc)
<br>

- **scope: :リソースの名前（ここではsession）って何してるの？**
    
    sessionsコントローラに相当するモデルが存在しないので、それに対応する受け皿となるフォームのオブジェクトを設定するために使用しています。
    
 
    例を挙げます。
    createアクションでユーザーのemailのパラメーターを取得するために、`user = User.find_by(email: params[:session][:email].downcase)` のように指示されているとします。その時のリクエストを見てみると、次のようになります。
    
    ```
    Processing by SessionsController#create as HTML
      Parameters: {"utf8"=>"✓","authenticity_token"=>"fboHRR7XfTbsN7SxgjLgLx3uWDzzj7HC1hi8H/q3zX7mQpHU. 2B8HwgVBXYqyLEaSt4rwxNWJGHeoworyY8MoLw==",
       "session"=>{"email"=>"メールアドレス", "password"=>"[FILTERED]"}, "commit"=>"Log in"}
    ```
    
    ※この時の`form_with`での送信データはデータベースに保存されるわけではなく、cookieとしてブラウザに保存されています
    
   コードの最後の行を見てみると、 “session”というキーの中に、更に"email"=>"メールアドレス", "password"=>"[FILTERED]"という別のハッシュが含まれているのが分かります。つまり**ハッシュの入れ子構造**になっています。
`params[:session][:email]`のように２つシンボルが続いているのは、入れ子になっている内部の方のキーを指しています。**:sessionを`form_with`内でスコープ指定することで、このような入れ子のハッシュのデータをデータベース無しで引き出すことができます**。

    このようにscopeを加えると、生成されるhtmlの属性の構造が変わり、そのおかげでモデルが無くてもグループ化してデータを引き渡すことが可能です。
    

## おわりに
`form_with`のまとめでした。
まとめるにあたって、Ajax関連のJavaScriptの理解やログイン情報のデータの流れが少しわかってきたので、よい学習になりました。同じような未経験の学習者の方々の助けになれば幸いです。

他にも様々な機能やオプションがありますので、気になった方はぜひご自身でも調べてみてくださいね。

## 参考サイト

[Rails 5.1〜7.0: ‘form_with’ APIドキュメント（翻訳）](https://techracho.bpsinc.jp/hachi8833/2022_01_06/39502)
[Rails：form_withのオプションや特徴について整理](https://qiita.com/yamaday0u/items/a3689bc48a7eff55929b)
[Ajaxとは？初心者向けに豊富な画像で仕組みを解説](https://pikawaka.com/word/ajax)
[form_withの:scopeオプション - プログラミング学習ノート](https://endoakak.hatenablog.com/entry/2020/08/29/200000)