1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails6】検索機能の実装

Last updated at Posted at 2020-12-19

#はじめに

記事の検索・閲覧ができるアプリケーションを作成しています。
今回は検索機能を'ransack'というgemを使用して実装したため、備忘録・復習のため記述します。

#環境

Ruby on Rails '6.0.0'
Ruby '2.6.5'

#前提

記事の投稿(articleテーブル)は作成済みで、ユーザーは記事の閲覧ができる状態。

#ransackとは

シンプルな検索フォームを実装できると共に、高度な検索フォームも作成することができるgemです。
このransackを導入することで、以下のメソッドが使用できるようになります。

  • _eqメソッド:条件にあった検索を行う
  • _contメソッド:部分一致
  • _iteqメソッド:「〜以下」という検索条件

他にも様々な検索に関するメソッドがありますが、今回は割愛します。

公式GitHubはこちらです。

#①gemの導入

Gemfile
gem 'ransack'
ターミナル
% bundle install

上記コマンドでgemを導入します。

#②ルーティングの記述

config/routes.rb
(中略)
get 'articles/search'

今回は、記事検索の機能を実装しているので、「articlesコントローラー」とします。
また検索機能は、「searchアクション」と命名しています。

#③コントローラー(articles)の記述

まず、全体を記載して、その後部分的に解説をしていきます。

app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  before_action :search_article, only: [:index, :search]
  def index
    @articles = Article.includes(:user).order('created_at DESC').limit(4)
    @ranks = Article.find(Like.group(:article_id).order('count(article_id) DESC').limit(4).pluck(:article_id))
  end

・・・(中略)・・・

  def search
    @results = @a.result(distinct: true).page(params[:page]).per(8).order('created_at DESC')
  end

  private

  def search_article
    @a = Article.ransack(params[:q])
  end
end
app/controllers/articles_controller.rb
  private

  def search_article
    @a = Article.ransack(params[:q])
  end

こちらの記述で、キー(:q)を使って、articlesテーブルから記事情報を探しています。そして、「@a」という名前の検索オブジェクトを生成しています。
この処理を行うメソッド名を「search_article」とし、index,searchアクションのみで使用するため、before_actionでの「only」で限定しています

app/controllers/articles_controller.rb
  def search
    @results = @a.result(distinct: true).page(params[:page]).per(8).order('created_at DESC')
  end

そして、この@aに対して、「.result」とすることで、検索結果を取得しています。

  • 「distinct: true」:重複するデータは除外して取得できる
  • .page(params[:page]).per(8).order('created_at DESC')」:kaminariというgemのページネーションを使用し、1つのページで8つの記事が作成順に表示されるようにしています。

#④viewファイルの記述

#####検索フォーム編

app/views/layouts/_search.html.erb
<%= search_form_for @a, url: articles_search_path do |f| %>
  <div class="search-wrapper">
    <div class="search-content col-12">
        <%= f.label :type_id_eq, '種類を選択', class: 'label' %>
        <div class="radio-btn">
          <%= f.radio_button :type_id_eq, '', {checked: true} %>指定なし
          <%= f.radio_button :type_id_eq, 1 %>補助金・助成金
          <%= f.radio_button :type_id_eq, 2 %>制度融資
        </div>
    </div>
    <div class="search-content col-12">
        <%= f.label :area_id_eq, '地域を選択', class: 'label' %>
        <%= f.collection_select(:area_id_eq, Area.all, :id, :name, {include_blank: "---"}, {class:"search-select-box float-right"}) %>
    </div>

・・・(中略)・・・

    <div class="search-content col-12">
        <%= f.label :title_or_infomation_cont, 'キーワード検索', class: 'label' %>
        <%= f.search_field :title_or_information_cont, placeholder: 'キーワードを入力', class:"search-form-control float-right" %>
    </div>
    <div class="search-content col-12 text-center">
      <%= f.submit 'この条件で検索する', class:"btn btn-outline-success search-btn" %>
    </div>
  </div>
<% end %>

部分的に解説していきます。

app/views/layouts/_search.html.erb
<%= search_form_for @a, url: articles_search_path do |f| %>

1行目部分です。search_form_forの引数に「@a(検索オブジェクト)」を渡すことで検索フォームを生成しています。

app/views/layouts/_search.html.erb
   <div class="search-content col-12">
        <%= f.label :type_id_eq, '種類を選択', class: 'label' %>
        <div class="radio-btn">
          <%= f.radio_button :type_id_eq, '', {checked: true} %>指定なし
          <%= f.radio_button :type_id_eq, 1 %>補助金・助成金
          <%= f.radio_button :type_id_eq, 2 %>制度融資
        </div>
    </div>
  • type_id_eqとすることで、ラジオボタンで選択したものと一致(=equal)するものを探します。type_idは記事のカラムとして含んでいます。
  • 「checked: true」とすることでdefaltで選択済みになります。
app/views/layouts/_search.html.erb
 <div class="search-content col-12">
        <%= f.label :area_id_eq, '地域を選択', class: 'label' %>
        <%= f.collection_select(:area_id_eq, Area.all, :id, :name, {include_blank: "---"}, {class:"search-select-box float-right"}) %>
    </div>
  • area_id_eqも同様に、areaが一致するものを探しています。
  • <%= f.collection_select ~ %>でプルダウンが生成されます。今回は記事投稿機能で事前にActiveHashを使用しAreaモデルを作成済みです。
app/views/layouts/_search.html.erb
 <div class="search-content col-12">
        <%= f.label :title_or_infomation_cont, 'キーワード検索', class: 'label' %>
        <%= f.search_field :title_or_information_cont, placeholder: 'キーワードを入力', class:"search-form-control float-right" %>
  </div>
  • 「title_or_information_cont」:今回記事のカラムの中で、titleとinformationの情報があり、その一部分の中でキーワードが合致するもの(_cont)を探しています。

#####検索結果編

app/views/articles/search.html.erb
<div class="container">
  <h5 class="article-title"><i class="fas fa-poll-h fa-2x my-orange"></i> 検索結果一覧</h5>
    <div class="row">
      <% if @results.length !=0 %>
          <% @results.each do |result| %>
            <div class="card-group col-md-6 col-lg-3">
              <%= link_to article_path(result.id), class: "article-link" do%>
                <span class="article-info"><%= result.genre.name %></span>
              <div class="card articles-chart">
                <%= image_tag result.image, class:"card-img-top" if result.image.attached? %> 
                  <div class="card-body">
                    <h5 class="card-title"><%= result.title %></h5>
                    <p class="card-text"><%= result.information.truncate(30) %></p>
                    <p class="like-button"><i class="far fa-heart fa-2x" style="color: #e82a2a;"></i><span style="color: #e82a2a"><%= result.likes.count %></span></p>
                  </div>
              </div>
              <% end %>
            </div>
          <% end %>
        <% end %>
      <% else %>
        <h5 class="alert">該当する投稿はありません!</h5>
      <% end %>
    </div>
</div>
  • <% if @results.length !=0 %>:検索結果があるかどうかで条件分岐を行い、あれば記事を表示、なければ「該当する投稿はありません!」を表示するようにしています。

以上で実装は完了です。

#おわりに

実装の一部分のため、わかりにくい表現があるかと思いますが、
不明点などあればご指摘ください。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?