LoginSignup
1
1

More than 3 years have passed since last update.

【rails】複数チェックボックス選択によるAND条件検索を実装してみた(サーバサイド)

Last updated at Posted at 2020-03-13

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

  1. tagsコントローラのsearchアクションは、選択されたチェックボックスの値(タグid)を、ストロングパラメータから配列で受け取る。

  2. tagsコントローラのsearchアクションは、配列で渡されたタグIDをタグメモモデル(中間テーブル)のメソッド「filter」に渡す。

  3. メソッド「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
  1. タグメモモデルに定義したメソッド「filter」は、引数のタグIDに紐づくメモIDを配列で取得する。 (selected_memo_ids = ...)
  2. 取得したメモIDの配列に格納された各メモIDについて、選択されたタグIDが紐づくかチェックする。 (break unless Memo.includes(:tags).find(id)...)
  3. チェックを通過したメモIDのみ配列で取得する。 (memo_filtered << id if ...)

もっとスマートな方法があるかな。。。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1