SIer企業で働く社会人4年目OLです。
仕事をやめる予定はないのですが、手に職をつけていつか副職ができるといいなと思いWEBアプリ開発の勉強し始めました。(2ヵ月くらい)
練習でWEBアプリ開発をしていますが、初めてつまったのがプルダウンメニューの作成なので勉強がてらまとめてみます。同じように悩んでる人の役に立てたらいいなと思います。
勉強始めたばかりなのでここ違うよ!っていうところがあればご指摘いただけると嬉しいです。
#やりたいこと
DB(Gameモデル)に格納しているデータをプルダウン(ドロップダウン)で選択して別のDB(Stageモデル)に保存したい。
####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
<!-- 新規登録アクション(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
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
ではなくてform_for
を使うのが一般的らしい。
#form_forで実装
RailsのインプットはProgateでしかしていないのでform_for
は初見だが、見よう見まねで実装してみた。
####新規登録用ページ(stage_a)のView
<!-- 新規登録アクション(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
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("保存するモデルのインスタンス", url: {送信先のアクション}) do |f|
本来なら送信先のアクションについても記載しなくても自動でルーティングしてくれるらしいが、うまくルーティングできなかったため記載した。
プルダウン形式は以下のf.collection.select
で実現できた。
f.collection_select(保存カラム,参照インスタンス,保存する参照先カラム,表示する参照先カラム)
ついでに、通常のテキストボックス(1行)は以下のf.text_field
。
f.text_field 保存カラム
form_forの使い方については【Rails】form_forの使い方をマスターしよう!のページがとても分かりやすかった。というよりRailsのヘルパーメソッドに基本的にこのサイトにまとめられているので今後参考にしていきたい。
#form_withで実装
from_for
について調べていたら、Rails5.1以降はform_with
を使用することが推奨されているとのこと。これについても見よう見まねで実装してみた。
####新規登録用ページ(stage_a)のView
<!-- 新規登録アクション(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
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_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を使うのが原則です。
モデルに紐づいたフォームか否かが使い分けの基準と理解した。
そして、form_with
はform_tag
とform_for
の機能をまとめたヘルパーメソッドである。form_with
の使用が推奨されていることから、Rails5.1以降を使用する場合はform_with
を使用すべきと考えてよいと思う。
#プルダウン同士の連携
プルダウンメニューは作れたが、次は別の問題が発生した。
1つ目のプルダウンを選択したら2つ目のプルダウンで選択できる内容が変更できるような入力フォームを作ろうと考えたが、Viewを更新しないとアクションにデータを渡せない。
これを解決するためにはAjaxを理解する必要があるようだが今は???状態なので調べて理解・実装したら、別の記事でまとめようと思う。