問題提起
作成したアプリでは、日報を入力する際に作業のジャンルも併せて入力する。例えば「腹筋10回した!」というときはあらかじめ設定した「運動」というジャンル。「参考書20p進んだ」なら「勉強」など。
ジャンルは予めユーザーが設定してそのあと選択肢にのってくるようにしていた。はじめは。
でもそれって面倒くさい。
「よし、日報書くぞ」
:ジャンル / 作業内容 / かかった時間
> 勉強 / 参考書20p / 1H
「あ、そういえば個人開発もやったんだ」
:ジャンル / 作業内容 / かかった時間
> 個人開発....
「ジャンルつくってなかった。ジャンル画面に遷移して、
ジャンルを新規作成でつくって、また戻って」
めんどうくさい。
自由記述/選択肢の共存
要は通常は選択肢から選び、ないなら自由記述でつくることができればいいのだ。
選択肢を出すヘルパーはselect_tagが有名だ。しかし、自由記述をやるなら、datalistでつくろう。
こんなかんじ。
app/views/reports/_form.html.erb
<!-- 略 -->
<div id="report_items">
<%= f.fields_for :report_items do |item| %>
<%= render "report_item_fields", f: item %>
<% end %>
<!-- 略 -->
</div>
<!-- 略 -->
app/views/reports/_report_item_fields.erb
<!-- 略 -->
<%= f.text_field :genre_name ,{:class => 'form-control' ,:list => 'datalistOptions3', :id => 'exampleDataList3' , :value => get_genre_name(f.object.genre_id) } %>
<datalist id="datalistOptions3">
<% @select_genre.each do |genre| %>
<option value= <%= genre.name %> >
<% end %>
<!-- 略 -->
text_field
のオプションとして:list
を追加。直後にそれと紐づくidのdatalistを作成する。datalistの中身はコントローラーでとってきたインスタンスをループで回してやる。
app/controllers/reports_controller.rb
#略
def new
@report = Report.new
@report.report_items.build
@select_genre = Genre.where(user_id: current_user)
end
自由に記述した場合は、日報追加時のcreateアクションの時にジャンルを新規追加してやればいい。
app/controllers/reports_controller.rb
#略...
def create
para = report_genre_params[:report_items_attributes]
report_lists = para.values
report_lists.each do |report|
genre_name = report[:genre_name]
if genre_name.nil?
report[:genre_id] = nil
break
end
@genre_new = Genre.find_by(name:genre_name,user_id: current_user)
if @genre_new.nil?
@genre_new = Genre.new("name"=> genre_name, "user_id" => current_user.id)
@genre_new.save
end
report[:genre_id] = @genre_new.id
end
# 略
private
def report_genre_params
params.require(:report).permit(:content, :reported_on, report_items_attributes: [:content, :genre_id, :genreset, :genre_name ,:work_hours, :content_for_share, :id])
end
そのようになった。
まとめ
めんどうくさい、という動作を減らしてつかいやすいものをつくる。そうするとうまくいく気がするなにごとも。