what
メモアプリで、メモに紐づくタグを複数選択することにより、AND条件で検索できるようにした。
why
メモの数が膨大になっても探せないメモはない説浮上のため。
前提条件
・rails 5.2.4.1
・メモアプリで、メモに紐づくタグをチェックボックスで選択し、絞り込み検索を実装する。
・メモとタグのモデルは多対多。
・メモモデルとタグモデルの中間テーブルは、tag_memo
ビュー(チェックボックス)
次の通り実装
【rails】チェックボックスを使ったAND条件による検索
https://qiita.com/igat/items/dc35d42889580026bb4d
サーバサイド
コントローラ
app/controllers/tags_controller.rb
...
def search
begin
selected_tag_ids = selected_tags_params # Tag id array checked with form.
filtered_memo_ids = Memo.filter(selected_tag_ids) # Memo id array filtered with checked tag by And condition.
@memos = Memo.where(id: filtered_memo_ids) # Memos instance selected with filtered memo ids.
rescue
redirect_to root_path
end
end
...
private
def selected_tags_params
params.require(:tag_ids)
end
-
tagsコントローラのsearchアクションは、選択されたチェックボックスの値(タグid)を、ストロングパラメータから配列で受け取る。
-
tagsコントローラのsearchアクションは、配列で渡されたタグIDをタグメモモデル(中間テーブル)のメソッド「filter」に渡す。
-
メソッド「filter」は選択された複数のチェックボックスに紐づくメモIDをAND条件で返す。
#####メソッド「filter」
app/models/tag_memo.rb
def self.filter(selected_tag_ids) # Tag id array checked with form.
selected_memo_ids = TagMemo.where(tag_id: selected_tag_ids).pluck(:memo_id).uniq.sort # Memo id array associated to checked tag.
return Memo.all unless selected_tag_ids
memo_filtered = [] # Memo id array associated to all tags checked with form.
selected_memo_ids.each do |id|
loop_count = 0
while selected_tag_ids.length > loop_count do
break unless Memo.includes(:tags).find(id).tags.pluck(:id).include?(selected_tag_ids[loop_count].to_i)
loop_count += 1; # Get memo id that associated tag id is equall to all tag id selected.
end
memo_filtered << id if loop_count == selected_tag_ids.length
end
return memo_filtered
end
- タグメモモデルに定義したメソッド「filter」は、引数のタグIDに紐づくメモIDを配列で取得する。
(selected_memo_ids = ...) - 取得したメモIDの配列に格納された各メモIDについて、選択されたタグIDが紐づくかチェックする。
(break unless Memo.includes(:tags).find(id)...) - チェックを通過したメモIDのみ配列で取得する。
(memo_filtered << id if ...)
もっとスマートな方法があるかな。。。