DEV Community

matt swanson
matt swanson

Posted on • Originally published at boringrails.com on

Use the Rails helper `highlight` when showing search results

Use the Rails highlight helper to wrap search result matches in <mark> tags.

Rails highlight helper

Highlight the search term “comment” in a list of notifcations

Usage

Pass the search term to your controller via params (e.g. params[:search]) and use that to filter down your results.

# app/controllers/inbox_controller.rb
class InboxController < ApplicationController
  def index
    @notifications = Current.user.notifications.for_search(params[:search])
  end
end

# app/models/notification.rb
class Notification < ApplicationRecord
  belongs_to :recipient, class_name: "User"

  validates :message, presence: true

  def self.for_search(term)
    if term.present?
      # Implement searching however you'd like
      where("message ILIKE ?", "%#{term}%")
    else
      all
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Render the notifications and use TextHelper#highlight on the message to emphasis the matching query.

<% @notifications.each do |notification| %>
  <%= link_to highlight(notification.message, params[:search]), notification %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

You can style the <mark> tag however you’d like.

mark {
  background-color: yellow;
}
Enter fullscreen mode Exit fullscreen mode

Options

You can pass either a string, array, or a regex as the phrase to match. Matches are case-insensitive.

highlight('Boring Rails is the best', 'rails')
# => Boring <mark>Rails</mark> is the best

highlight('Boring Rails is the best', /rails|best/)
# => Boring <mark>Rails</mark> is the <mark>best</mark>

highlight('Boring Rails is the best', ['is', 'best'])
# => Boring Rails <mark>is</mark> the <mark>best</mark>
Enter fullscreen mode Exit fullscreen mode

If there are no matches or you leave the phrase blank, everything still works fine.

highlight('Boring Rails is the best', 'JavaScript')
# => Boring Rails is the best

highlight('Boring Rails is the best', '') # nil works too
# => Boring Rails is the best
Enter fullscreen mode Exit fullscreen mode

You can also override the HTML markup wrapped around the matches using the highlighter option. Use \1 to reference the match. The output is sanitized by default

highlight('Boring is best', 'best', highlight: '<b>\1</b>')
# => Boring is <b>best</b>

highlight('Boring is best', 'best', highlight: '<a href="tagged?q=\1">\1</a>')
# => Boring is <b>best</b>
Enter fullscreen mode Exit fullscreen mode

If you need to run additional code, you can pass a block to render instead.

highlight('Blog: Boring Rails', 'rails') do |match|
  link_to(match, public_share_path(term: match))
end
# => Blog: Boring <a href="/public/share?term=Rails">Rails</a>
Enter fullscreen mode Exit fullscreen mode

Additional Resources

Rails API Docs: TextHelper#highlight


Top comments (0)