【Rails】ransackを使わずに1つの検索バーで複数テーブルのデータを検索する

本記事は [駆け出しエンジニアの第一歩！AdventCalendar2020 9日目](https://qiita.com/advent-calendar/2020/programming-beginner)の記事です。

# 作りたいもの

下図のように一つの検索バーで複数のテーブルのデータを取得する機能を実装します。
下図ではMagicテーブル、Productテーブル、Userテーブルの3つのテーブルに検索をかけて、それぞれのテーブルで検索条件にヒットするデータを取得し、タブで表示を切り替えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620431/0fc5f398-32e6-5e0a-a463-e6f6f75bac4f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620431/3ed1eec3-b2a7-ac5a-f254-0311d711cfff.png)

# やることまとめ
1.検索機能のルーティングを設定する。
2.ビューに検索バーを実装する。
3.コントローラに検索機能を実装する。

# 1.検索機能のルーティングを設定する

検索ボタンがクリックされた時に、どのコントローラのどのアクションを呼び出すかをroute.rbに記載します。
下記例では、homes_controller.rbのsearchアクションを呼び出すようにしています。

```Ruby:route.rb

# 検索機能実施
get '/search' => 'homes#search', as: 'search'

```


# 2.ビューに検索バーを実装する

次に検索フォームを用意します。
私の場合はヘッダーに検索フォームを表示させたかったので、_header.html.erbに下記コードを実装しました。

```erb:_header.html.erb

<%= form_with url: search_path, method: :get, local: true do |f| %>

  <!-- 検索フォーム -->
  <%= f.text_field :content, :placeholder => "マジック動画タイトル、商品名、ユーザー名で検索" %>

  <!-- 検索ボタン -->
  <%= f.button :type => "submit" do %>
    <i class='fas fa-search'></i>
  <% end %>

<% end %>

```

### 解説

```erb

<%= form_with url: search_path, method: :get, local: true do |f| %>
```

form_withヘルパーを用いて、検索条件をコントローラまで渡してあげます。
ここでは、URLに/searchを指定し、getメソッドでアクセスするという内容を書いています。


```erb

<!-- 検索フォーム -->
<%= f.text_field :content, :placeholder => "マジック動画タイトル、商品名、ユーザー名で検索" %>
```

f.text_fieldは検索フォームの検索ワードを入力するinput要素を指しています。
入力した検索ワードは:contentに格納されます。(後ほどコントローラで開封します。)



```erb

<!-- 検索ボタン -->
<%= f.button :type => "submit" do %>
  <i class='fas fa-search'></i>
<% end %>
```
form_withヘルパーではsubmitボタンをクリックすると、指定のルーティング先へ遷移するようになっています。
ここではそのsubmitボタンを虫眼鏡アイコンにする処理を書いています。


# 3.コントローラに検索機能を実装する

コントローラでは、form_withヘルパーより送られてきた検索ワード(:content)を受け取り、それを基に3つのテーブルそれぞれで検索をかけています。

```Ruby:homes_controller.rb

# 検索機能
def search
  # 検索ワード
  content = params['content']
  # 投稿検索結果
  @magics = partical_magic(content)
  # 商品検索結果
  @products = partical_product(content)
  # ユーザー検索
  @users = partical_user(content)
end

private

# 投稿検索
def partical_magic(content)
  Magic.where('title LIKE ?', "%#{content}%")
end

# 商品検索
def partical_product(content)
  Product.where('name LIKE ?', "%#{content}%")
end

# ユーザー検索
def partical_user(content)
  User.where('display_name LIKE ?', "%#{content}%")
end
```

### 解説

```Ruby

# 検索ワード
content = params['content']
```

form_withヘルパーから送られてきたパラメータ:contentの中身、すなわち検索ワードをcontent変数に格納しています。

```Ruby

# 投稿検索結果
@magics = partical_magic(content)
# 商品検索結果
@products = partical_product(content)
# ユーザー検索
@users = partical_user(content)
```

検索結果用のインスタンス変数を3つ用意し、それぞれに検索結果を格納しています。
それぞれの式の右辺では検索を行うメソッドに先ほど格納したcontent変数を引数として渡しています。


```Ruby

# 投稿検索
def partical_magic(content)
  Magic.where('title LIKE ?', "%#{content}%")
end

# 商品検索
def partical_product(content)
  Product.where('name LIKE ?', "%#{content}%")
end

# ユーザー検索
def partical_user(content)
  User.where('display_name LIKE ?', "%#{content}%")
end
```

それぞれのテーブルに対して検索を行い、データを返すメソッドです。
モデル名.where('[検索対象カラム] LIKE ?', "%#{content}%")
という式になっています。
上記例は部分一致検索となっております。

# おわりに

検索結果画面も載せられればと思ったのですが、かなり複雑になっていたので今回は割愛させてもらいました…汗