search
LoginSignup
0
Help us understand the problem. What are the problem?

posted at

updated at

検索機能の実装

検索機能の実装

概要

  • 学習マッチングサイトを作成する。ユーザーが講座を作成して、ユーザー間で売買を行う。バイヤー側が、講座を様々な条件で検索できるようにしたい。
  • 具体的には、カテゴリー、受講形態(オンラインかオフラインか)、アクセス先(住所かURLか)、価格(上限)、タグで検索できるようにしたい。
  • カテゴリー、受講形態、アクセス先、価格はand検索、タグはor検索にしたい。

アソシエーション

0b5fbcf246ecc3190132d23b59ea7a28.png

テーブル定義

  • Lessonsテーブル
    Image from Gyazo
  • Categoriesテーブル
    Image from Gyazo
  • Tagsテーブル
    Image from Gyazo
  • TagListsテーブル
    Image from Gyazo

Lessonsコントローラ

Image from Gyazo
検索画面ではsearchメソッドが呼ばれ、検索結果表示画面ではresultメソッドが呼ばれる。

and検索としてのsearchメソッド

Image from Gyazo
カテゴリー、受講形態、アクセス先、価格、それぞれを別々の検索メソッドとして定義し、それをメソッドチェーンで繋げることでand検索を実現している。

scopeについて

scope機能とは、モデル側であらかじめ特定の条件式に対して名前をつけて定義し、その名前でメソッドの様に条件式を呼び出すことが出来る仕組みのこと。

class モデル名 < ApplicationRecord
 scope :スコープの名前, -> { 条件式 }
end

が基本構文であり、条件式に合致する値を返す。さらに、

class モデル名 < ApplicationRecord
 scope :スコープの名前, -> (引数){ 条件式 }
end

このように引数を渡すことができる。今回は、受け取ったparamsを引数に渡して、各条件式に適用している。

whereについて

今回は、全てプレースホルダーを使った書き方をしている。こちらの方が引数を渡す際には、後々変更を加えたりすることを考えて、シンボル指定や文字列指定よりも扱いやすい気がする。

カテゴリー検索

Image from Gyazo
category_idを受け取り、category_idが合致するものを検索している。「if category_id.present?」により、category_idがない場合は、実行されない。

受講形態検索

Image from Gyazo
attending_style(オンラインかオフライン)を受け取り、合致するものを検索している。attending_styleがない場合は実行されない。

アクセス先検索

Image from Gyazo
フォームに入力された文字列(access)を元に、あいまい検索を行う。そのために、LIKEを使用する。「%#{access}%」とすることで、入力された文字列を含むものを全て抽出できる。

価格検索

Image from Gyazo
選択された価格(price)以下の価格であるものを検索している。priceがない場合は実行されない。

searchメソッドにまとめる

Image from Gyazo
各検索メソッドをメソッドチェーンで繋ぎ、それをsearchメソッドとして定義している。入力された値がない場合にはreturnで離脱させる。scope の {} の部分は do...end に置き換え可能であるらしいので、今回はこのブロック構文を使用した。

ストロングパラメータについて

Image from Gyazo
検索画面から送られたparameterに対して、許可処理を行っているが、require[:search]とすると、params[:search]が空であった場合に、エラーが発生する。そのため、今回はfetchメソッドを使用する。
fetchメソッドは
ハッシュ.fetch(:キー, デフォルト値)
と書く。
指定したキーの値を取得し、存在しない場合にはデフォルト値を返す。このため、空であった場合でもエラーをなくすことができる。
あとは、permitメソッドを使って、必要な情報のみを取得するようにする。

タグをor検索する

Image from Gyazo
if...endでタグの情報がある場合にのみ、or検索が実行されるようにしている。

該当するtagのidを配列に格納する

Image from Gyazo
params[:search][:tags]は先頭に空文字を含む配列であるため、selectメソッドを使って、空文字を排除してからtag_idsに格納している。
select(&:present?) は、基本構文である select{|tag| tag.present?}と同じ挙動である。上記の書き方の方が処理速度が少し早いらしいです。

該当するtagのtag_listを配列に格納する

Image from Gyazo
TagListモデルの空のインスタンスを生成する。
Image from Gyazo
orメソッドとwhere句を組み合わせることで、tag_idが合致するtag_listを全て@tag_listsに格納している。

該当するlessonを配列に格納する

Image from Gyazo
Lessonモデルの空のインスタンスを生成する。
Image from Gyazo
上記の方法と同じで、orメソッドとwhere句を組み合わせて、tag_listのlesson_idとidが合致するlessonを全て@lessons に格納している。

修正!

以下のように修正した。
Image from Gyazo
この記事を書きながら、tagがない場合にand検索できないことに気づいた。そのため、tagがある場合を、
Image from Gyazo
とした。params[:search][:tag]は先頭に空文字が入るため、最低でも1つの要素を持つ配列であるため、lengthが1より大きい場合にはtagがあると判断できる。
tagがない場合には、else以下の処理が実行され、and検索のみが実行されるようにした。

まとめ

ポートフォリオが形になって2ヶ月程度が経って、自分のやったことを言語化するために、本記事を作成したが、改めて見るとかなり間違いが多く、それにも気づけたことはかなりの収穫であったと思います。
以下が参考にしたリンクです。
【Rails】複数の条件の検索機能を作る。日付範囲検索を行う
railsで複数ワードでの検索機能(and)とマイナス検索機能(-)を実装してみる
Rails 5 の or を色々試してみた

【Rails】 モデルのスコープ機能(scope)の使い方を1から理解する
Rubyにおけるブロック構文(do~end)の使い方
【初心者必見】Rubyのselectメソッドの基礎から応用まで解説

【Rails】 whereメソッドを使って欲しいデータの取得をしよう!
【SQL】基本だけど重要!条件式の設定”WHERE句”について解説。
Ruby on Railsでor条件のSQLで検索する方法を解説
Active Record クエリインターフェイス

はじめてのRuby!fetchメソッドの使いかたをマスターしよう!
【Rails】 permitメソッドを使ってストロングパラメーターにしよう

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?