RailsOmnibar
Add an Omnibar to Ruby on Rails.
Installation
Add rails_omnibar
to your bundle and add the following line to your config/routes.rb
:
mount RailsOmnibar::Engine => '/rails_omnibar'
You can pick any path.
To limit access, do something like this:
authenticate :user, ->(user){ user.superadmin? } do
mount RailsOmnibar::Engine => '/rails_omnibar'
end
Configuration
# app/lib/omnibar.rb
Omnibar = RailsOmnibar.configure do |c|
c.max_results = 5 # default is 10
# Render as a modal that is hidden by default and toggled with a hotkey.
# The default value for this setting is false - i.e. render inline.
c.modal = true # default is false
# Use a custom hotkey to focus the omnibar (or toggle it if it is a modal).
# CTRL+<hotkey> and CMD+<hotkey> will both work.
c.hotkey = 't' # default is 'k'
# Add static items that can be found by fuzzy typing.
# "suggested" items will be displayed before user starts typing.
c.add_item(title: 'Important link', url: 'https://www.disney.com', suggested: true)
c.add_item(title: 'Important info', modal_html: '<b>You rock</b>')
# Add all backoffice URLs as searchable items
Rails.application.routes.routes.each do |route|
next unless route.defaults[:action] == 'index'
next unless name = route.name[/^backoffice_(.+)/, 1]
# items can have icons
c.add_item(title: name.humanize, url: route.format({}), icon: :cog)
end
# Add commands
# This command will allow searching users by id by typing e.g. 'u123'.
# The capture group is used to extract the value for the DB query.
c.add_record_search(
pattern: /^u(\d+)/,
example: 'u123',
model: User,
)
# Search records by column(s) other than id (via LIKE query by default)
c.add_record_search(
pattern: /^u (.+)/,
example: 'u Joe',
model: User,
columns: %i[first_name last_name],
)
# The special #add_help method must be called last if you want a help entry.
# It shows a modal with descriptions and examples of the commands, e.g.:
#
# * Search User by id
# Example: `u123`
# * Search User by first_name OR last_name
# Example: `u Joe`
# * Search User by id
# Example: `U123`
# * Search Google
# Example: `g kittens`
# * Get count of a DB table
# Example: `COUNT users`
#
c.add_help
end
Render it somewhere. E.g. app/views/layouts/application.html.erb
:
<%= Omnibar.render %>
Using multiple different omnibars
UserOmnibar = Class.new(RailsOmnibar).configure { ... }
AdminOmnibar = Class.new(RailsOmnibar).configure { ... }
UserOmnibar.render
AdminOmnibar.render
Other options and usage patterns
# Add multiple items
MyOmnibar.add_items(
*MyRecord.all.map { |rec| { title: rec.title, url: url_for(rec) } }
)
# Add ActiveAdmin index routes as searchable items
Admin::UsersController # trigger autoloading (use your own AA namespace)
ActiveAdmin.application.namespaces.first.resources.each do |res|
index = res.route_collection_path rescue next
title = res.&.label.presence || next
MyOmnibar.add_item(title: title, url: index)
end
# Render in ActiveAdmin (`MyOmnibar.modal = true` recommended)
module AddOmnibar
def build_page(...)
within(super) { text_node(MyOmnibar.render) }
end
end
ActiveAdmin::Views::Pages::Base.prepend(AddOmnibar)
# Add all index routes as searchable items
Rails.application.routes.routes.each do |route|
next unless route.defaults.values_at(:action, :format) == ['index', nil]
MyOmnibar.add_item(title: route.name.humanize, url: route.format({}))
end
# Custom record lookup and rendering
MyOmnibar.add_record_search(
pattern: /^U(\d+)/,
example: 'U123',
model: User,
finder: ->(id) { User.find_by(admin: true, id: id) },
itemizer: ->(user) { { title: "Admin #{user.name}", url: admin_url(user), icon: :user } }
)
# Custom search, plus mapping to multiple results
MyOmnibar.add_search(
description: 'Google',
pattern: /^g (.+)/,
example: 'g kittens',
finder: ->(value) { GoogleSearch.fetch(value) },
itemizer: ->(res) do
[
{ title: res.title, url: res.url },
{ title: "#{res.title} @archive", url: "web.archive.org/web/#{res.url}" }
]
end,
)
# Completely custom command
MyOmnibar.add_command(
description: 'Get count of a DB table',
pattern: /COUNT (.+)/i,
example: 'COUNT users',
resolver: ->(value, ) do
{ title: value.classify.constantize.count.to_s }
rescue => e
{ title: e. }
end,
)
Development
Setup
- Clone the repository
- Go into the directory
- Run
bin/setup
to install Ruby and JS dependencies
License
This program is provided under an MIT open source license, read the LICENSE.txt file for details.