Search
Finding what you're looking for fast is essential. That's why Avo leverages ransack's powerful query language.
INFO
While we show you examples using ransack, you can use other search engines, so ransack is not mandatory.
First, you need to add ransack as a dependency to your app (breaking change from Avo v1.10).
# Gemfile
gem 'ransack'Enable search for a resource
To enable search for a resource, you need to configure the search class attribute to the resource file.
class Avo::Resources::User < Avo::BaseResource
self.search = {
query: -> { query.ransack(name_eq: q).result(distinct: false) }
}
endThe query block provides the q variable, which contains the stripped search query string, and the query variable on which you run the query. That ensures that the authorization scopes have been appropriately applied. If you need access to the unstripped query string, you can use params[:q] instead of q.
In this block, you may configure the search however strict or loose you need it. Check out ransack's search matchers to compose the query better.
WARNING
If you're using ransack version 4 and up you must add ransackable_attributes and maybe more to your model in order for it to work. Read more about it here.
Custom search provider
Since v3.10.8You can use custom search providers like Elasticsearch. In such cases, or when you want to have full control over the search results, the query block should return an array of hashes. Each hash should follow the structure below:
{
_id: 1,
_label: "The label",
_url: "The URL",
_description: "Some description about the record", # only with Avo Pro and above
_avatar: "URL to an image that represents the record", # only with Avo Pro and above
_avatar_type: :rounded # or :circle or :square; only with Avo Pro and above
}Example:
class Avo::Resources::Project < Avo::BaseResource
self.search = {
query: -> do
[
{ _id: 1, _label: "Record One", _url: "https://example.com/1" },
{ _id: 2, _label: "Record Two", _url: "https://example.com/2" },
{ _id: 3, _label: "Record Three", _url: "https://example.com/3" }
]
end
}
endWARNING
Results count will not be available with custom search providers.
Authorize search
Search is authorized in policy files using the search? method.
class UserPolicy < ApplicationPolicy
def search?
true
end
endIf the search? method returns false, the search operation for that resource is not going to show up in the global search and the search box on index is not going to be displayed.
If you're using search? already in your policy file, you can alias it to some other method in you initializer using the config.authorization_methods config. More about that on the authorization page.
Avo.configure do |config|
config.authorization_methods = {
search: 'avo_search?',
}
endConfigure the search result
-> title
By default, the search results will be displayed as text. By default search title will be the resource title.

You may configure that to be something more complex using the item -> title option. That will display it as the title of the search result.
class Avo::Resources::Post < Avo::BaseResource
self.search = {
query: -> { query.ransack(name_cont: q, m: "or").result(distinct: false) },
item: -> do
{
title: "[#{record.id}]#{record.name}",
}
end
}
end
-> description
You might want to show more than just the title in the search result. Avo provides the item -> description option to add some more information.
class Avo::Resources::Post < Avo::BaseResource
self.search = {
query: -> { query.ransack(name_cont: q, m: "or").result(distinct: false) },
item: -> do
{
title: "[#{record.id}]#{record.name}",
description: record.truncated_body
}
end
}
end
-> image_url
You may improve the results listing by adding an image to each search result. You do that by using the item -> image_url attribute that is an url to a image.
class Avo::Resources::Post < Avo::BaseResource
self.search = {
query: -> { query.ransack(name_cont: q, m: "or").result(distinct: false) },
item: -> do
{
title: "[#{record.id}]#{record.name}",
description: ActionView::Base.full_sanitizer.sanitize(record.body).truncate(130),
image_url: main_app.url_for(record.cover_photo),
}
end
}
end-> image_format
The image you add to a search result can have a different format based on what you set on the item -> image_format attribute. You may choose between three options: :square, :rounded or :circle.
class Avo::Resources::Post < Avo::BaseResource
self.search = {
query: -> { query.ransack(name_cont: q, m: "or").result(distinct: false) },
item: -> do
{
title: "[#{record.id}]#{record.name}",
description: ActionView::Base.full_sanitizer.sanitize(record.body).truncate(130),
image_url: main_app.url_for(record.cover_photo),
image_format: :rounded
}
end
}
end-> help
You may improve the results listing header by adding a piece of text highlighting the fields you are looking for or any other instruction for the user. You do that by using the help attribute. This attribute takes a string and appends it to the title of the resource.

class Avo::Resources::Post < Avo::BaseResource
self.search = {
query: -> { query.ransack(id_eq: q, m: "or").result(distinct: false) },
help: -> { "- search by id" }
}
end-> result_path
By default, when a user clicks on a search result, they will be redirected to that record, but you can change that using the result_path option.
class Avo::Resources::City < Avo::BaseResource
self.search = {
query: -> { query.ransack(name_eq: q).result(distinct: false) },
result_path: -> { avo.resources_city_path record, custom: "yup" }
}
end-> hide_on_global
You might have a resource that you'd like to be able to perform a search on when on its Index page but not have it present in the global search. You can hide it using hide_on_global: true.
class Avo::Resources::TeamMembership < Avo::BaseResource
self.search = {
query: -> { query.ransack(id_eq: q, m: "or").result(distinct: false) },
item: -> do
{
description: record.level,
}
end,
hide_on_global: true
}
endResource search
When a resource has the search attribute with a valid configuration, a new search input will be displayed on the Index view.

Global search
License: ProAvo also has a global search feature. It will search through all the resources that have the search attribute with a valid configuration.
You open the global search input by clicking the trigger on the navbar or by using the CMD + K keyboard shortcut (Ctrl + K on Windows).

Hide the global search
If you, by any chance, want to hide the global search, you can do so using this setting 👇
# config/initializers/avo.rb
Avo.configure do |config|
config.disabled_features = [:global_search]
endSince version 3.13.5 disabled_features become callable. Within this block, you gain access to all attributes of Avo::ExecutionContext
# config/initializers/avo.rb
Avo.configure do |config|
config.disabled_features = -> { current_user.is_admin? ? [] : [:global_search] }
endScope out global or resource searches
You may want to perform different searches on the global search from the resource search. You may use the params[:global] flag to figure that out.
class Avo::Resources::Order < Avo::BaseResource
self.search = {
query: -> {
if params[:global]
# Perform global search
query.ransack(id_eq: q, m: "or").result(distinct: false)
else
# Perform resource search
query.ransack(id_eq: q, details_cont: q, m: "or").result(distinct: false)
end
}
}
endSearching within associations
In some cases, you might need to search for records based on attributes of associated models. This can be achieved by adding a few things to the search query. Here's an example of how to do that:
Assuming you have two models, Application and Client, with the following associations:
# app/models/application.rb
class Application < ApplicationRecord
belongs_to :client
end
# app/models/client.rb
class Client < ApplicationRecord
has_many :applications
endYou can perform a search on Application records based on attributes of the associated Client. For example, searching by the client's email, name, or phone number:
# app/avo/resources/application.rb
class Avo::Resources::Application < Avo::BaseResource
self.search = {
query: -> {
query
.joins(:client)
.ransack(
id_eq: q,
name_cont: q,
workflow_name_cont: q,
client_id_eq: q,
client_first_name_cont: q,
client_last_name_cont: q,
client_email_cont: q,
client_phone_number_cont: q,
m: 'or'
).result(distinct: false)
}
}
endIn the above example, ransack is used to search for Application records based on various attributes of the associated Client, such as client_email_cont and client_phone_number_cont. The joins method is used to join the applications table with the clients table to perform the search efficiently.
This approach allows for flexible searching within associations, enabling you to find records based on related model attributes.
Results count
Since v3.11By default, Avo displays 8 search results whenever you search. You can change the number of results displayed by configuring the search_results_count option:
Avo.configure do |config|
config.search_results_count = 16
endYou can also change the number of results displayed on individual resources:
class Avo::Resources::User < Avo::BaseResource
self.search = {
results_count: 5
query: -> {},
}
endYou can also assign a lambda to dynamically set the value.
class Avo::Resources::User < Avo::BaseResource
self.search = {
results_count: -> { user.admin? ? 30 : 10 }
}
endIf you configure results_count by specifying it in the resource file then that number takes precedence over the global search_results_count for that resource.
Friendly.rb - Your friendly European Ruby Conference