【Ralis6】検索結果で一致したキーワードを強調(ハイライト)する方法

検索結果で一致したキーワードを強調(ハイライト)する方法

今回の実装完了イメージは下記の様な画像です。

検索キーワードを強調ハイライト

その為に、検索したキーワードに一致する文字を強調して表示するためのHelperを作ります。

前提条件

投稿機能がある。

今回で言うと、Postテーブルにtitleとcontentカラムが存在します。

検索機能の実装

まずは、検索機能を実装します。

僕の場合は、ヘッダーに検索窓を埋め込みました。

application.html.erb

<%= form_with url: search_path, local: true, method: :get do |form| %>
<%= form.text_field :keyword, :value => @keyword, placeholder: "キーワードで探す", :required => true %>
<%= button_tag :type => "submit", :name => nil do %>
<i class="fas fa-search"></i>
<% end %>
<% end %>

検索ボタンにはフォントオーサムを使用しています。

表示されない方は、まずはフォントオーサムを表示できる様に設定しましょう。

【爆速】Rails6にフォントオーサム(Font Awesome 5)を導入する方法

posts_controller.rb

  def search
    @keyword = params[:keyword]
    @keywords = @keyword.split(/[[:blank:]]+/)
    @keywords.each do |keyword|
      @posts = Post.where("title like :q OR content like :q ", q: "%#{keyword}%")
    end
    @posts = @posts.order(id: :DESC).page(params[:page])
  end

これで、空白区切り(半角、全角)で、2語以上の検索もできます。

.page(params[:page]) の部分はkaminariのgemでページネーションを実装しているので、導入していない方は記述しなくて大丈夫です。

search.html.erb

<% if @posts.present? %>
<div class="loop-content-article-ttl">
  <h1>「<b><%= params[:keyword] %>」</b>の検索結果<span><%= @posts.total_count %>件</span></h1>
  <p><%= @posts.current_page %> / <%= @posts.total_pages %> ページ</p>
</div>
<ul class="loop-content-article-list">
  <% @posts.each do |post| %>
  <%= render 'l-article', post: post %>
  <% end %>
</ul>
<%= paginate @posts %>
<% else %>
<div class="loop-content-article-nosearch">
  <p>「<b><%= params[:keyword] %></b>」の検索結果はありませんでした。</p>
  <p&gt;キーワードを変更してもう一度検索してください。</p>
</div>
<% end %>

こちらにもkaminariを使用していますので、ページ数の表示やページネーション を入れているタグは、導入していない方は記述しなくて大丈夫です。

_l-article.html.erb

<h2><%= post.title %></h2>
<p><%= post.content.truncate(110).delete '#,`,*,\,' %>&lt;/p>

出力は他ページにも使いまわしているので、テンプレート化しています。

検索結果で一致したキーワードを強調

ここからが今回の目的の実装です。

posts_helper.rb

module PostsHelper
  def emphasize_keyword(content, keyword)
    keyword = keyword.split(/[[:blank:]]+/)
    content_array = content.split(/\R/)
    first_match_line = content_array.find { |e| /#{keyword}/ =~ e }

    trancate_line = if first_match_line.present?
                      truncate(first_match_line, length: 110).delete '#,`,*,\,'
                    else
                      truncate(content, length: 110).delete '#,`,*,\,'
                    end

    highlight(trancate_line, keyword, :highlighter => '<span class="keyword-highlight">\1</span>')
  end
end
  • 検索キーワードに一致する本文を1行を抜き出す
  • 抜き出した本文を100文字に省略する
  • 検索キーワードに一致する文字を太字にする

上記の実装をhelperにまとめています。

scssは下記の様にしました。

// 検索キーワードハイライト
.keyword-highlight {
  background: #fff093;
  font-weight: 700;
  padding: 2px 3px;
  font-style: italic;
}

_l-article.html.erb

あとはviewでhelperを使います。

<% if current_page?(search_path) %>
<h2><%= emphasize_keyword(post.title, @keyword) %></h2>
<% else %>
<h2><%= post.title %></h2>
<% end %>
<% if current_page?(search_path) %>
<p><%= emphasize_keyword(post.content, @keyword) %></p>
<% else %>
<p><%= post.content.truncate(110).delete '#,`,*,\,' %></p>
<% end %>

これで実装完了です!

あとはブラウザで検索してみて、ハイライトされているのを確認してください!

検索キーワードを強調ハイライト

他にもこんな記事があります!