Tip: Use the Rails helper `highlight` when showing search results
Use the Rails highlight
helper to wrap search result matches in <mark>
tags.
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
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 %>
You can style the <mark>
tag however you’d like.
mark {
background-color: yellow;
}
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>
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
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', highlighter: '<b>\1</b>')
# => Boring is <b>best</b>
highlight('Boring is best', 'best', highlighter: '<a href="tagged?q=\1">\1</a>')
# => Boring is <a href=\"tagged?q=best\">best</a>
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>
Additional Resources
Rails API Docs: TextHelper#highlight