LoginSignup
0
0

More than 3 years have passed since last update.

[Rails] 複数カラムに対する複数単語の検索フォーム

Posted at

はじめに

料理レシピ検索投稿サイト作成に伴い、検索機能の実装しました。
複数の単語で、かつ、関連モデルのカラムに対しても検索できるフォームにしました。

環境

Rails 5.2.4.4
MySQL 5.7.31

テーブル構成

RecipesとIngredientsを多対多の関係で紐づけています。
このrecipesのtitleカラムとingredientsのnameカラムに対して検索できるものを作ります。
(必要のないカラムは省略しています)
Image from Gyazo

実装

1. ルーティング

routes.rb
resources :recipes do
    collection do
        get 'search'
    end
end

2. コントローラー

/controllers/recipes_controller.rb
def search
        redirect_to recipes_path if params[:search] == ""
        @array_searches = params[:search].split(/[[:blank:]]+/)
        @recipes = []
        @array_searches.each do |search|
            next if search == "" 
            recipes = Recipe.joins(:ingredients)
            @recipes += recipes.where('ingredients.name LIKE ? ', "#{search}%").or(recipes.where('title LIKE ?', "#{search}%"))
        end
        @recipes.uniq!
end

redirect_to recipes_path if params[:search] == ""
  paramsが空だった場合、recipes_pathに移動させます。

@array_searches = params[:search].split(/[[:blank:]]+/)
  paramsをsplitで分割させますが、split(" ")だと半角スペースしか対応できません。
  空白文字の正規表現[:blank:]を使用し、連続した空白にも対応できるようにします。

@recipes = []
  空の配列を用意します。

@array_searches.each do |search|
  分割したparamsをひとつずつ検索にかけるため、繰り返し文に入れます。

next if search == ""
  これがないと、先頭に空白が入った時、全てのレコードにヒットします。

recipes = Recipe.joins(:ingredients)
  .joinsを用い、RecipesとIngredientsを内部結合させます。
  Ingredientsのnameカラムに対しても検索をかけるためです。

あとは、前方一致で検索をかけ、.uniq!で重複した検索結果がでないようにします。

3. ビュー

/views/recipes/index.html.erb
<%= form_with(url: search_recipes_path, local: true, method: :get) do |f| %>
    <%= f.text_field :search, placeholder: "Search Recipes" %>
    <%= f.submit "Search" %>
<% end %>

参考にした記事

https://qiita.com/Orangina1050/items/ca4e5dc26e0a32ee3137
https://qiita.com/nao58/items/bf5d017a06fc33da9e3b

0
0
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
0
0