前提
アソシエーション
-
LeagueモデルとTeamモデルには1:nのアソシエーションがあるとします。
league.rb
# リーグモデル
class League < ApplicationRecord
has_many :teams
end
team.rb
# チーム(大学)モデル
class Team < ApplicationRecord
belongs_to :league
end
やりたいこと
- 以下のHTMLを生成させたいです。
<!-- チーム名を入力するためのセレクトボックス -->
<select name="event[top_team]" id="event_top_team">
<option value="">選択してください</option>
<optgroup label="1部リーグ">
<option value="aa大学">aa大学</option>
<option value="bb大学">bb大学</option>
<option value="cc大学">cc大学</option>
<option value="dd大学">dd大学</option>
</optgroup>
<optgroup label="2部リーグ">
<option value="ee大学">ee大学</option>
<option value="ff大学">ff大学</option>
<option value="gg大学">gg大学</option>
<option value="hh大学">hh大学</option>
</optgroup>
<optgroup label="3部リーグ">
<option value="ii大学">ii大学</option>
<option value="jj大学">jj大学</option>
<option value="kk大学">kk大学</option>
<option value="ll大学">ll大学</option>
</optgroup>
<optgroup label="入替戦">
<option value="1部4位大学">1部4位大学</option>
<option value="2部1位大学">2部1位大学</option>
<option value="2部4位大学">2部4位大学</option>
<option value="3部1位大学">3部1位大学</option>
</optgroup>
</select>
問題点
- アソシエーションを使って選択肢がグループ化されたセレクトボックスを生成する
grouped_collection_selectメソッドというものがあり、それを使えば記述量少なく書けそうですが、「入替戦」グループの値はテーブルのデータではないため、その部分が実装できません。
_form.html.erb
<%= f.grouped_collection_select(:top_team, League.all, :teams, :name, :name, :name, {include_blank: '選択してください'} %>
<!-- これでは「入替戦」グループの値を出力できない -->
最初に到達した解決策
- ビュー側の
selectメソッドに配列(下の例でいうselect_box)を渡すことで解決しようとしました。 - そのアプローチはとりあえず良いと思ったのですが、その配列を生成する方法が少し冗長に思えました。
-
selectメソッド(DBからデータを取得する際に、指定カラムのデータのみ取得するもの)や、collection_singular_idsメソッドの存在は知っていたため、冗長に見えたのかと思います(なんかもうちょっといい書き方ありそう、みたいな軽い感じですが。。。)
event.rb
def self.make_team_select_box
leagues = League.all.order(name: :asc)
select_box = []
leagues.each do |league|
league_teams = []
league_teams << league.name
# ここから
teams = league.teams
team_names = []
teams.each do |team|
team_names << team.name
end
# ここまでが冗長?
# -> 要するに、「チーム名の配列をもっと手軽に生成したい」ということになる
league_teams << team_names
select_box << league_teams
end
select_box << ['入替戦', ['1部4位大学', '2部1位大学', '2部4位大学', '3部1位大学']]
end
_form.html.erb
<%= f.select :team, Event.make_team_select_box, {include_blank: '選択してください'} %>
最終的に到達した解決策
- ビュー側は上記のままです。
- 先ほど冗長に思えた配列生成の部分で、より良い書き方を調べていると、
pluckメソッドがはまりました。 -
pluckメソッドは、データ取得結果から指定したカラムのデータのみを配列にして返します。
event.rb
def self.make_team_select_box
leagues = League.all.order(name: :asc)
select_box = []
leagues.each do |league|
league_teams = []
league_teams << league.name
league_teams << league.teams.pluck(:name)
select_box << league_teams
end
select_box << ['入替戦', ['1部4位大学', '2部1位大学', '2部4位大学', '3部1位大学']]
end