良いこと思いつたと思って、一回これをやって先輩に怒られたので真似しない方がいいです。
ただ自分的に結構おもしろいなあと思ったのでメモ。
概要
株式会社万葉の新入社員教育用カリキュラムのタスク管理アプリを使います。
既に@yokku21 さんが終わらせたものをフォークしてきました(どうもありがとうございました)。
タスク一覧画面では、タスクをタスク名、ステータス、優先度、ラベルで絞り込むことができ、さらにそれらを並び替えることができます。
今回、ここを一行にしてみたいと思います。
プルリク
ビフォーアフター
ビフォー(イメージ)
# app/controllers/tasks_controller.rb
def index
@tasks = current_user.tasks.with_title(params[:title]).
with_status(params[:status]).
with_priority(params[:priority]).
with_label_ids(params[:label_ids]).
sorted_by(params[:sort_option])
end
既にイイ感じに@yokku21さんが仕上げてくれています、、、!
- 補足:
- これらのスコープの命名規則はこちらに従っています。
- スコープをチェーンできるようにblankが来た時はnextを返す処理にしています。
アフター
# app/controllers/tasks_controller.rb
def index
@tasks = current_user.tasks.filtered_by(filter_params)
end
一行!!ナニコレめっちゃスリム!
解説
1). 検索用フォームのname属性はスコープの名前にしとく
<!-- 例: app/views/tasks/index.html.erb -->
<%= f.text_field(:with_title, ...) %>
<%= f.select(:with_status, ...) %>
<%= f.select(:with_priority, ...) %>
<%= f.select(:with_priority, ...) %>
<%= f.collection_check_boxes(:with_label_ids, ...) %>
2). コントローラにて検索で使うparamsだけを取得できるようにしとく
# 例: app/controllers/tasks_constolle.rb
private
def filter_params
params.permit(
:with_title,
:with_status,
:with_priority,
:sorted_by,
with_label_ids: [],
).delete_if{|key, value| value.blank? }.to_h
end
3). スコープの親分を作る
# 例: app/models/task.rb
scope :filtered_by, -> (filter_params) do
filter_params.inject(self) do |task, param|
task.send(param[0], param[1])
end
end
たたみこみ演算と初期値をselfとすることで、チェーンしながらスコープを呼んでいきます。
4). 完成
# app/controllers/tasks_controller.rb
def index
@tasks = current_user.tasks.filtered_by(filter_params)
end