やりたいこと
個人開発でやっているサービス「lytnote」の改善を行いたい。目標一覧画面にはユーザーが登録した目標が並んでいる。それぞれにはステータスがあって、完了や中止や進行中が選べる。振り返りの際に目標のステータスを変更するのだ。
目標A 状態:進行中
目標B 状態:完了
目標C 状態:中止
目標D 状態:完了
....
でも使っていくと、目標がどんどん増えてしまう。進行中の目標のみを絞り込んで表示したい。
目標の絞り込みを行うぞ。
フロー
目標一覧画面表示
↓
絞り込みたいステータスをプルダウンで選ぶ
↓
絞り込みボタンを押す
↓
絞り込まれる
これでやっていこう。つくるものを考える。
- 一覧画面にプルダウン表示
- コントローラー修正
- jsファイル修正
- 一覧画面に部分テンプレート追加
1. 一覧画面にプルダウン表示
<%# 略 %>
<%= form_with url: plans_path, method: :get, local: false do |f| %>
<%= f.select :status, ["進行中","中止/完了","全て"] ,{class: "form-control"}%>
<%= f.submit "絞り込み" ,{class: "btn-primary"}%>
<% end %>
<%# 略 %>
local: false
がポイントだ。これによってフォームの送信がAjaxで行われることになる。
2. コントローラー修正
Ajax通信になってもコントローラーのいく先は同じである。今回はindexアクションに飛ばすようにしている。ただ飛ばすだけでなく、プルダウンの中の値を確認し、それによって引き出すデータを絞り込んでいる。
class PlansController < ApplicationController
# 色々略
def index
# 色々略
plans_nonorder = Plan.includes(:review_items).where(user_id: current_user.id).page(params[:page])
if params[:status].present?
if params[:status] == "進行中"
filterd_plans = plans_nonorder.where(status:"進行中")
elsif params[:status] == "中止/完了"
filterd_plans = plans_nonorder.where(status:"中止").or(plans_nonorder.where(status:"完了"))
else
filterd_plans = plans_nonorder
end
else
filterd_plans = plans_nonorder
end
@plans = filterd_plans.order(deadline: :desc)
# 略
end
# 略
params[:status]
にプルダウンの値が入ってくる。
3. jsファイル修正
Ajax通信が行われると、コントローラーに飛んだ後はindex.js.erb
にゆく。
var plans = document.querySelector("#plan_list");
plans.innerHTML = '<%= j render 'planlist' %>';
これはビューファイルのid = plan_list
で囲まれた箇所のみを書き換える処理である。
4. 一覧画面に部分テンプレート追加
ここまでだけだとうまくいかないので、部分テンプレートをつくる。目標一覧画面を修正する。
<%# 略 %>
<%= form_with url: plans_path, method: :get, local: false do |f| %>
<%= f.select :status, ["進行中","中止/完了","全て"] ,{class: "form-control"}%>
<%= f.submit "絞り込み" ,{class: "btn-primary"}%>
<% end %>
<div id="plan_list">
<%= render partial: 'planlist' %>
</div>
<%# 略 %>
部分テンプレートは頭に_
をつけて作成する。
<% @plans.each.with_index(1) do |plan, i| %>
<%= plan.name %>
<%= plan.status %>
<% end %>
本当はデザインの関係でdivとかいっぱいあるけど、省略している。
5. ページネーションも追加する
これだけだとページネーションの処理がうまくいかない。部分テンプレートのところを修正する。
<% @plans.each.with_index(1) do |plan, i| %>
<%= plan.name %>
<%= plan.status %>
<% end %>
<% if @plans.empty? %>
<%# ページネーション非表示 %>
<% else %>
<nav aria-label="Page navigation example">
<ul class="pagination">
<%= paginate @plans, remote: true %>
</ul>
</nav>
<% end %>
このremote: true
が重要。これによってページネーションもAjax通信で行われ、部分テンプレートの箇所のみが更新される。
うごく
おわり
今月はずっとこれをやっていたのでうまくいってよかった。次はいよいよ振り返り機能を見直していくぞ。