CodeBox CodeBox

【Rails】gemを使わずに複数モデルから検索する方法

Ruby / Rails

概要

今回は複数テーブルからデータを検索する方法について解説していきます。検索機能を簡単に実装できるransackというgemがありますが、今回は使わずに実装しています。またAPIモードでRailsアプリを作成しているので、Viewのコードは記載しません。

準備編

CustomerとTeamというモデルを作成します。作業手順は別記事にまとめていますので、こちらを参考にしてください。

検索機能の実装編

検索機能といってもどのようなUI(見た目)や要件にするかで実装方法は異なります。今回はよくある2パターンを例に挙げて解説していきます。

例① 検索ボックスが1つの場合

要件は下記の通りです。

  • 検索ボックスは1つ
  • 検索ワードにCustomer名が入力されたら、合致するCustomer を表示する
  • 検索ワードにTeam名が入力されたら、そのTeamに属するCustomerを表示する
  • 検索ワードが空の場合、Customer全件表示する
  • 部分一致(特定の文字を含むか)


1.Customerモデルにメソッドを追加する

検索を行うメソッドをcustomer.rbに追加します。

# 今回の場合、selfは"Customer"という意味になる
def self.search(keyword)
    if keyword != ""
        teams = Team.where('name like ?', "%#{keyword}%")
        if(teams.present?)
            customer_teams = CustomerTeam.where(team_id: teams.ids)
            customer_team_id = customer_teams.pluck(:customer_id)
            Customer.where(id: customer_team_id) 
        else
            Customer.where('name like ?', "%#{keyword}%")
        end
    else
        Customer.all
    end
end


searchメソッドの前にselfがついていますが、これは『クラスメソッド』である印です。今回はCustomer.search(...)のようにクラスに対して、使用したいメソッドなのでselfが必要となります。

# OKな場合(Customerというクラスに対してsearchメソッドを使用している)
@customers = Customer.search(keyword)

# NGな場合(customerというインスタンスに対してsearchメソッドを使用している)
@customers = customer.serach(keyword)


2.コントローラーで検索するメソッドを使う

モデルで作成したメソッドを使います。

class CustomersController < ApplicationController
  # GET /customers
  def index
    keyword = params[:keyword]
    @customers = Customer.search(params[:keyword])
    render json: @customers
  end
end


これで実装は完了です。

paramsに関する補足

params[:keyword]にはユーザーが入力したワードが文字列で入っています。params[:keyword]とすると検索ワードの値が取れるのか確認するため、コントローラーに一文追加してみましょう。

class CustomersController < ApplicationController
  # GET /customers
  def index
    keyword = params[:keyword]
    p params # ここを追記
    @customers = Customer.search(params[:keyword])
    render json: @customers
  end
end


次にURLを/customers?keyword=テストとして、再読み込みします。そうするとターミナルには下記のように表示されます。

Parameters: {"keyword"=>"テスト"}


Parametersの部分は”params”と同じなので、このようになります。

params = {"keyword" => "テスト"}

# keywordの中身を取り出したければparams[:keyword]とする
# params[:keyword] 
# => "テスト"


例② 検索ボックスが1つ & ラジオボタン(or セレクトボックス)の場合

要件は下記の通りです。

  • 検索ボックスは1つ
  • ラジオボタンでCustomer or Teamどちらのテーブルから検索するか選択可能
  • 部分一致(特定の文字を含むか)


1.コントローラーにメソッドを追加

typeとkeywordで検索できるようにコントローラーに独自メソッドを作成します。

[customers_controller.rb]

def search_by_params
  type = params[:type]
  keyword = params[:keyword]

  if type == "Customer"
    @customers = Customer.where('name like ?', "%#{keyword}%")
    render json: @customers
  elsif type == "Team"
    @teams = Team.where('name like ?', "%#{keyword}%")
    render json: @teams
  else
    @customers = Customer.all
    render json: @customers
  end
end


2.ルーティングを追加

検索するためのルーティングを追加します。

[routes.rb]

Rails.application.routes.draw do
  (省略)
  get 'search_by_params' => 'customers#search_by_params'
end


挙動の確認をするため、URLを"/search_by_params?type=Team&keyword=サンプル"とし再読み込みします。Team名が"サンプル"のデータが表示されればOKです。

解説は以上です。