【Rails】DBと連携してプルダウン（ドロップダウン）メニューをつくる（勉強中）

SIer企業で働く社会人4年目OLです。
仕事をやめる予定はないのですが、手に職をつけていつか副職ができるといいなと思いWEBアプリ開発の勉強し始めました。（2ヵ月くらい）

練習でWEBアプリ開発をしていますが、初めてつまったのがプルダウンメニューの作成なので勉強がてらまとめてみます。同じように悩んでる人の役に立てたらいいなと思います。

勉強始めたばかりなのでここ違うよ！っていうところがあればご指摘いただけると嬉しいです。

#やりたいこと
DB(Gameモデル)に格納しているデータをプルダウン（ドロップダウン）で選択して別のDB(Stageモデル)に保存したい。

![プルダウン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797344/7cf713aa-8ecb-463d-be5e-c472248c215f.png)
###モデル設計

####Gameモデル
|  カラム  |  型  |
| ---- | ---- |
|  id  |  integer  |
|  game_name  |  text  |
####Stageモデル
|  カラム  |  型  |
| ---- | ---- |
|  id  |  integer  |
|  game_id ※ |  integer  |
|  stage_name  |  text  |
※Stageのgame_idがGameのidを外部参照しているイメージ

#form_tagで実装
これまでユーザからの入力は全部`form_tag`で実現していたので、まずはそれでむりやり実装したみた。
####新規登録用ページ（stage_a）のView

~~~html
<!-- 新規登録アクション（stage_n）にデータ渡す -->
<%= form_tag("/stage_n") do %>
  <div class="form">
    <div class="form-body">
      <p>game_name</p>
      <select name="game_name">
        <%@games.each do |game|%>
          <option value=<%="#{game.game_name}"%>><%=game.game_name%></option>
        <%end%>
      </select>
      <p>stage_name</p>
      <input type="text" name="stage_name">
      <input type="submit" value="保存">
    </div>
  </div>
<% end %>
~~~
####新規登録用のController
~~~ruby
  def stage_a
    @games = Game.all
  end

  def stage_n
    @game = Game.find_by(game_name: params[:game_name])
    @stage = Stage.new(game_id: @game.id,stage_name: params[:stage_name])
    @stage.save
  end
~~~

####新規登録用ページ（stage_a）のブラウザでの見え方
![form_tag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797344/c75d698e-5bf5-1185-cfa1-b73ac1f139ba.png)

期待値通りにできた。のでこれでいいのかとも思ったが、ネットで検索してみるとそもそもモデルに紐づいたユーザ入力は`form_tag`ではなくて`form_for`を使うのが一般的らしい。

#form_forで実装
RailsのインプットはProgateでしかしていないので`form_for`は初見だが、見よう見まねで実装してみた。
####新規登録用ページ（stage_a）のView
~~~html
<!-- 新規登録アクション（stage_n）にデータ渡す -->
<%= form_for("@stage", url: {controller: 'home', action: 'stage_n' }) do |f|%>
  <div class="form">
    <div class="form-body">
      <p>game_name</p>
      <%= f.collection_select(:game_id,@games,:id,:game_name)%>
      <p>stage_name</p>
      <%= f.text_field :stage_name%>
      <%= f.submit "保存"%>
    </div>
  </div>
<% end %>
~~~
####新規登録用のController
~~~ruby
  def stage_a
    @games = Game.all
    @stage = Stage.new
  end

  def stage_n
    Stage.create(stage_params)
    redirect_to("/stage_view")
  end

    private
    def stage_params
      params.require(:@stage).permit(:stage_name, :game_id)
    end
~~~

####新規登録用ページ（stage_a）のブラウザでの見え方
![form_for.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797344/8f2c8256-9c79-60fa-474e-326f7ee09c16.png)

なんとか期待値通りになった。無理にループを自分で実装しなくてもよくてすっきりと記述できた。

~~~ruby
form_for("保存するモデルのインスタンス", url: {送信先のアクション}) do |f|
~~~

本来なら送信先のアクションについても記載しなくても自動でルーティングしてくれるらしいが、うまくルーティングできなかったため記載した。
プルダウン形式は以下の`f.collection.select`で実現できた。

~~~ruby
f.collection_select(保存カラム,参照インスタンス,保存する参照先カラム,表示する参照先カラム)
~~~

ついでに、通常のテキストボックス（1行）は以下の`f.text_field`。

~~~ruby
f.text_field 保存カラム
~~~

form_forの使い方については[【Rails】form_forの使い方をマスターしよう！](https://pikawaka.com/rails/form_for)のページがとても分かりやすかった。というよりRailsのヘルパーメソッドに基本的にこのサイトにまとめられているので今後参考にしていきたい。

#form_withで実装
`from_for`について調べていたら、Rails5.1以降は`form_with`を使用することが推奨されているとのこと。これについても見よう見まねで実装してみた。
####新規登録用ページ（stage_a）のView
~~~html
<!-- 新規登録アクション（stage_n）にデータ渡す -->
<%= form_with(model: @stage, url: {controller: 'home', action: 'stage_n'} ,local: true) do |form|%>
  <div class="form">
    <div class="form-body">
      <p>game_name</p>
      <%= form.collection_select(:game_id,@games,:id,:game_name)%>
      <p>stage_name</p>
      <%= form.text_field :stage_name%>
      <%= form.submit "保存"%>
    </div>
  </div>
<% end %>

~~~
####新規登録用のController
~~~ruby
  def stage_a
    @games = Game.all
    @stage = Stage.new
  end


  def stage_n
    @stage=Stage.new(game_id: params[:stage][:game_id],stage_name: params[:stage][:stage_name] )
    @stage.save
    redirect_to("/stage_view")
  end
~~~

####新規登録用ページ（stage_a）のブラウザでの見え方
![form_with.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/797344/c7fa7afa-e640-a9c2-af51-d5c096120981.png)

これも他と変わらずに期待値通り。正直`form_for`とそんなに変わらないじゃんと思った。参考にしたページの記述に似せたためControllerに多少違いはあるが、同じ書き方をしても問題ないと思っている。（試してはいない）
#form_tagとform_forとform_withについて

それぞれの使い分けについてもざっくり調べてみた。まず、`form_tag`と`form_for`については以下のサイトが参考になった。

>Railsのform_for/form_tagの分け方の意図としては、
>
>form_for: 任意のmodelに基づいたformを作るときに使う
>form_tag: modelに基づかないformを作るときに使う
>
>ということです。
>つまり、あるuserモデルに基づいたuserを作成するときはform_forを使い、
>そうではなく、検索窓のような何のモデルにも基づかないformを作りたいときはform_tagを使うのが原則です。
>
>[【Rails】form_for/form_tagの違い・使い分けをまとめた](https://qiita.com/shunsuke227ono/items/7accec12eef6d89b0aa9)

モデルに紐づいたフォームか否かが使い分けの基準と理解した。

そして、`form_with`は`form_tag`と`form_for`の機能をまとめたヘルパーメソッドである。`form_with`の使用が推奨されていることから、Rails5.1以降を使用する場合は`form_with`を使用すべきと考えてよいと思う。


#プルダウン同士の連携

プルダウンメニューは作れたが、次は別の問題が発生した。
1つ目のプルダウンを選択したら2つ目のプルダウンで選択できる内容が変更できるような入力フォームを作ろうと考えたが、Viewを更新しないとアクションにデータを渡せない。

これを解決するためにはAjaxを理解する必要があるようだが今は？？？状態なので調べて理解・実装したら、別の記事でまとめようと思う。