Global Search
Overviewâ
Global Search provides a unified search experience across multiple models in your CmAdmin panel. Users can press â + K (Mac) or Ctrl + K (Windows) to open a search modal from anywhere on the platform. It searches records using the existing :search filters on each model's index action, respects Pundit policies and scopes, and returns up to 5 matching records per model.
In addition to record results, the search also suggests matching model pages (e.g., typing "user" suggests navigating to the Users index page).
Featuresâ
- Keyboard shortcut â Open search with â + K / Ctrl + K from any page.
- Cross-model search â Search across all configured models in a single query.
- Policy-aware â Only shows results the current user is authorized to see.
- Concurrent execution â Searches models in parallel using a configurable thread pool.
- Keyboard navigation â Navigate results with Arrow keys and press Enter to visit.
- Model suggestions â Suggests matching model pages alongside record results.
- Customizable subtitle fields â Control which fields appear below each search result.
- Custom display name â Define
cm_display_nameon your model to control the result title.
Setupâ
Step 1 â Register models for global searchâ
In your CmAdmin initializer (e.g., config/initializers/zcm_admin.rb), add the models you want to be searchable:
CmAdmin.configure do |config|
config.global_search_models = [User, Post, Order]
end
Note: The order of models in this array determines the display order of results.
Step 2 â Ensure a search filter existsâ
Each model must have a :search filter defined in its cm_index block. Global search uses this filter to query records.
cm_admin do
cm_index do
filter %i[email first_name last_name], :search, placeholder: 'Search by name or email'
column :first_name
column :last_name
column :email
end
end
Important: If a model does not have a
:searchfilter on its index action, it will be silently skipped during global search.
Step 3 â Define cm_display_nameâ
By default, search results display as "ModelName #id" (e.g., "User #42"). To show a more meaningful title, define cm_display_name on your model:
class User < ApplicationRecord
def cm_display_name
"#{first_name} #{last_name}"
end
end
class Post < ApplicationRecord
def cm_display_name
title
end
end
Step 4 â Customize subtitle fieldsâ
Each search result can display additional metadata below the title. By default, global_search_fields is set to [:id, :created_at, :updated_at]. You can override this per model by setting the global_search_fields attribute:
cm_admin do
self.global_search_fields = %i[email status created_at]
cm_index do
filter %i[email first_name], :search
column :email
column :status, field_type: :tag
column :created_at, field_type: :date
end
end
Note: The fields listed in
global_search_fieldsmust also be defined as columns incm_index. Only columns that exist in the index view and pass theirdisplay_ifcondition will be shown.
Configuration Referenceâ
CmAdmin.config.global_search_modelsâ
| Property | Type | Default | Description |
|---|---|---|---|
global_search_models | Array | [] | Array of ActiveRecord model classes to include in global search results. |
global_search_fields (per model)â
| Property | Type | Default | Description |
|---|---|---|---|
global_search_fields | Array | [:id, :created_at, :updated_at] | Array of field identifiers to display as subtitle in search results. |
Environment Variablesâ
| Variable | Default | Description |
|---|---|---|
GLOBAL_SEARCH_THREAD_POOL_SIZE | 5 | Number of threads used for concurrent model searches. |
How It Worksâ
- User opens the search modal via â + K / Ctrl + K or by clicking the search icon.
- After typing at least 2 characters, a debounced request (300ms) is sent to the server.
- The server iterates over
global_search_modelsin parallel threads. - For each model:
- Checks if the user has
indexpolicy access. - Checks if a
:searchfilter is defined on the index action. - Applies policy scopes and default scopes.
- Runs the search filter and limits results to 5 records.
- Checks if the user has
- Results are sorted by the original model order and rendered via Turbo Stream.
- Additionally, model pages matching the query string are suggested at the bottom.
Full Exampleâ
# config/initializers/zcm_admin.rb
CmAdmin.configure do |config|
config.global_search_models = [User, Post, Comment]
end
# app/models/user.rb
class User < ApplicationRecord
def cm_display_name
"#{first_name} #{last_name}"
end
cm_admin do
set_icon 'fa fa-user'
self.global_search_fields = %i[email created_at]
cm_index do
filter %i[email first_name last_name], :search, placeholder: 'Search users'
column :first_name
column :last_name
column :email
column :created_at, field_type: :date
end
end
end
# app/models/post.rb
class Post < ApplicationRecord
def cm_display_name
title
end
cm_admin do
set_icon 'fa fa-file-text'
self.global_search_fields = %i[status created_at]
cm_index do
filter %i[title], :search, placeholder: 'Search posts'
column :title
column :status, field_type: :tag
column :created_at, field_type: :date
end
end
end
Notesâ
- Models without a
:searchfilter or without index policy access are automatically excluded. - The search respects all default scopes and action-level scopes configured on the model.
- The search modal will not open if another modal is already visible on the page.
- The placeholder in the search input automatically shows the first 3 configured model names.