Integrations / Frameworks / Rails / Search
Aug. 21, 2019

Traditional search implementations tend to have search logic and functionality on the back end. This made sense when the search experience consisted of a user entering a search query, executing that search, and then being redirected to a search result page.

Implementing search on the back end is no longer necessary. In fact, in most cases it is harmful to performance because of added network and processing latency. We highly recommend the usage of our InstantSearch libraries issuing all search requests directly from the end user’s browser, mobile device, or client. It will reduce the overall search latency while offloading your servers at the same time.

To create real-time search experience, you can use our InstantSearch libraries.

Built on top of the JavaScript client, InstantSearch is a set of components to help you build your search. It comes in different flavors for all popular JavaScript frameworks:

We recommend building a frontend search experience to perform queries directly from the end-user browser without going through your server; there are, however, some cases where you want to search in the back end.

A search returns ORM-compliant Rails model objects. Your back end will search through Algolia but then load models directly from the database.

1
2
hits =  Contact.search("jon doe")
p hits

The search method will accept any search parameters as second argument.

1
2
# dynamical search parameters
p Contact.search('jon doe', { hitsPerPage: 5, page: 2 })

Some search parameters can be set in the index settings. This is recommended if you find yourself always passing the same search parameters.

1
2
3
4
5
6
7
8
9
10
class Contact < ActiveRecord::Base
  include AlgoliaSearch

  algoliasearch do
    # default search parameters stored in the index settings
    minWordSizefor1Typo 4
    minWordSizefor2Typos 8
    hitsPerPage 42
  end
end

Each ORM object returned is enriched with highlight_result attribute from Algolia’s raw response. See Highlighting & Snippeting documentation

1
hits[0].highlight_result['first_name']['value']

If you want to retrieve something from the original raw Algolia response, you can access it from the response array.

1
2
3
hits =  Contact.search("jon doe")
p hits.raw_answer['nbHits']
p hits.raw_answer['nbPages']

If you don’t need models, you can avoid loading objects from the database and get the Algolia raw json response directly.

1
2
3
4
json_answer = Contact.raw_search("jon doe")
p json_answer
p json_answer['hits']
p json_answer['facets']

Searching in a specific index

In some cases, you may need to specify the index name when searching. It typically happens when you use the add_index method in your model configuration. In this case, you can pass the index key in the second argument, along with search parameters.

1
2
Book.search 'foo bar', index: 'Book_by_editor'
Book.raw_search 'foo bar', index: 'Book_by_editor'

The replica key is also available. Internally, it’s the same as index but it’s more explicit.

1
2
Book.search 'foo bar', replica: 'Book_by_editor'
Book.raw_search 'foo bar', replica: 'Book_by_editor'

Back end Pagination

Even if we highly recommend to perform all search (and therefore pagination) operations from your front end using JavaScript, we support both will_paginate and kaminari as pagination back ends.

To use :will_paginate, specify the :pagination_backend in your global configuration:

1
2
3
4
5
AlgoliaSearch.configuration = {
  application_id: 'YourApplicationID',
  api_key: 'YourAdminAPIKey',
  pagination_backend: :will_paginate
}

Then, as long as you use the search method, the returning results will be a paginated set:

1
2
3
4
5
6
7
8
9
# in your controller
@results = MyModel.search('foo', hitsPerPage: 10)

# in your views
# if using will_paginate
<%= will_paginate @results %>

# if using kaminari
<%= paginate @results %>

Faceting

Facets can be retrieved calling the extra facets method of the search array response.

To be able to retrieve facets, the necessary attributes must be defined as attributesForFaceting. Read more in the index settings section.

1
2
3
4
5
hits = Contact.search('jon doe', { facets: '*' })
p hits                    # ORM-compliant array of objects
p hits.facets             # extra method added to retrieve facets
p hits.facets['company']  # facet values+count of facet 'company'
p hits.facets['zip_code'] # facet values+count of facet 'zip_code'
1
2
raw_json = Contact.raw_search('jon doe', { facets: '*' })
p raw_json['facets']

Search for facet values

Sometimes you have so many different values for your facets that you wish you could search through them. Good news, Algolia can search for facet values, as long as you qualified the searchableAttribute as searchable](/doc/guides/managing-results/refine-results/faceting/#declaring-a-searchable-attribute-for-faceting).

1
Product.search_for_facet_values('category', 'Headphones') # Array of {value, highlighted, count}

This method can also take any parameter a query can take. This will adjust the search to only hits which would have matched the query.

1
2
3
4
5
# Only sends back the categories containing red Apple products (and only counts those)
Product.search_for_facet_values('category', 'phone', {
  query: 'red',
  filters: 'brand:Apple'
}) # Array of phone categories linked to red Apple products

Did you find this page helpful?