⚡ The Meilisearch integration for Ruby on Rails 💎
**Meilisearch Rails** is the Meilisearch integration for Ruby on Rails developers. **Meilisearch** is an open-source search engine. [Discover what Meilisearch is!](https://github.com/meilisearch/meilisearch) ## Table of Contents - [📖 Documentation](#-documentation) - [🤖 Compatibility with Meilisearch](#-compatibility-with-meilisearch) - [🚀 Getting Started](#-getting-started) - [⚙️ Settings](#️-settings) - [🔍 Custom search](#-custom-search) - [🪛 Options](#-options) - [Meilisearch configuration & environment](#meilisearch-configuration--environment) - [Index configuration](#index-configuration) - [Custom attribute definition](#custom-attribute-definition) - [Custom primary key](#custom-primary-key) - [Conditional indexing](#conditional-indexing) - [Share a single index](#share-a-single-index) - [Queues & background jobs](#queues--background-jobs) - [Relations](#relations) - [Sanitize attributes](#sanitize-attributes) - [UTF-8 encoding](#utf-8-encoding) - [Manual operations](#manual-operations) - [Indexing & deletion](#indexing--deletion) - [Access the underlying index object](#access-the-underlying-index-object) - [Development & testing](#development--testing) - [⚙️ Development workflow & contributing](#️-development-workflow--contributing) - [👏 Credits](#--credits) ## 📖 Documentation The whole usage of this gem is detailed in this README. To learn more about Meilisearch, check out our [Documentation](https://docs.meilisearch.com/learn/tutorials/getting_started.html) or our [API References](https://docs.meilisearch.com/reference/api/). ## 🤖 Compatibility with Meilisearch This package only guarantees the compatibility with the [version v0.28.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.28.0). ## 🔧 Installation This package requires Ruby version 2.6.0 or later and Rails 5.2 or later. With `gem` in command line: ```bash gem install meilisearch-rails ``` In your `Gemfile` with [bundler](https://bundler.io/): ```ruby source 'https://rubygems.org' gem 'meilisearch-rails' ``` ### Run Meilisearch There are many easy ways to [download and run a Meilisearch instance](https://docs.meilisearch.com/reference/features/installation.html#download-and-launch). For example, if you use Docker: ```bash docker pull getmeili/meilisearch:latest # Fetch the latest version of Meilisearch image from Docker Hub docker run -it --rm -p 7700:7700 getmeili/meilisearch:latest meilisearch --master-key=masterKey ``` NB: you can also download Meilisearch from **Homebrew** or **APT**. ## 🚀 Getting Started #### Configuration Create a new file `config/initializers/meilisearch.rb` to setup your `MEILISEARCH_HOST` and `MEILISEARCH_API_KEY` ```ruby MeiliSearch::Rails.configuration = { meilisearch_host: 'YourMeilisearchHost', # example: http://localhost:7700 meilisearch_api_key: 'YourMeilisearchAPIKey', } ``` The gem is compatible with [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord), [Mongoid](https://github.com/mongoid/mongoid) and [Sequel](https://github.com/jeremyevans/sequel). #### Add documents The following code will create a `Book` index and add search capabilities to your `Book` model. ```ruby class Book < ActiveRecord::Base include MeiliSearch::Rails meilisearch do attribute :title, :author # only the attributes 'title', and 'author' will be sent to Meilisearch # all attributes will be sent to Meilisearch if block is left empty end end ``` ⚠️ Note that even if you want to use all the default options, you must declare an empty `meilisearch` block in your model. #### Basic Backend Search We **strongly recommend the use of front-end search** through our [JavaScript API Client](https://github.com/meilisearch/meilisearch-js/) or [Instant Meilisearch plugin](https://github.com/meilisearch/instant-meilisearch) Search returns ORM-compliant objects reloaded from your database. ```ruby # Meilisearch is typo-tolerant: hits = Book.search('harry pottre') hits.each do |hit| puts hit.title puts hit.author end ``` #### Backend Pagination This gem supports: - [kaminari](https://github.com/amatsuda/kaminari) - [pagy](https://github.com/ddnexus/pagy) - [will_paginate](https://github.com/mislav/will_paginate). Specify the `:pagination_backend` in the configuration file: ```ruby MeiliSearch::Rails.configuration = { meilisearch_host: 'YourMeilisearchHost', meilisearch_api_key: 'YourMeilisearchAPIKey', pagination_backend: :kaminari #:will_paginate } ``` Then, as soon as you use the `search` method, the returning results will be paginated: ```ruby # controller @hits = Book.search('harry potter') # views <% @hits.each do |hit| %> <%= hit.title %> <%= hit.author %> <% end %> <%= paginate @hits %> # if using kaminari <%= will_paginate @hits %> # if using will_paginate ``` The **number of hits per page defaults to 20**, you can customize it by adding the `hits_per_page` parameter to your search: ```ruby Book.search('harry potter', hits_per_page: 10) ``` #### Extra Configuration Requests made to Meilisearch may timeout and retry. To adapt the behavior to your needs, you can change the parameters during configuration: ```ruby MeiliSearch::Rails.configuration = { meilisearch_host: 'YourMeilisearchHost', meilisearch_api_key: 'YourMeilisearchAPIKey', timeout: 2, max_retries: 1, } ``` ## ⚙️ Settings You can configure the index settings by adding them inside the `meilisearch` block as shown below: ```ruby class Book < ApplicationRecord include MeiliSearch::Rails meilisearch do searchable_attributes [:title, :author, :publisher, :description] filterable_attributes [:genre] sortable_attributes [:title] ranking_rules [ 'proximity', 'typo', 'words', 'attribute', 'sort', 'exactness', 'publication_year:desc' ] synonyms nyc: ['new york'] # The following parameters are applied when calling the search() method: attributes_to_highlight ['*'] attributes_to_crop [:description] crop_length 10 end end ``` Check the dedicated section of the documentation, for more information on the [settings](https://docs.meilisearch.com/reference/features/settings.html). ## 🔍 Custom search All the supported options are described in the [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html) section of the documentation. ```ruby Book.search('Harry', attributes_to_highlight: ['*']) ``` 👉 Don't forget that `attributes_to_highlight`, `attributes_to_crop`, and `crop_length` can be set up in the `meilisearch` block of your model. ## 🔍 Sorted search As an example of how to use the sort option, here is how you could achieve returning all books sorted by title in ascending order: ```ruby Book.search('*', sort: ['title:asc']) ``` 👉 Don't forget to set up the `sortable_attributes` option in the `meilisearch` block of your model. ## 🪛 Options ### Meilisearch configuration & environment #### Custom index_uid By default, the **index_uid** will be the class name, e.g. `Book`. You can customize the index_uid by using the `index_uid:` option. ```ruby class Book < ActiveRecord::Base include MeiliSearch::Rails meilisearch index_uid: 'MyCustomUID' end ``` #### Index UID according to the environment You can suffix the index UID with the current Rails environment by setting it globally: ```ruby MeiliSearch::Rails.configuration = { meilisearch_host: 'YourMeilisearchHost', meilisearch_api_key: 'YourMeilisearchAPIKey', per_environment: true } ``` This way your index UID will look like this `"Book_#{Rails.env}"`. ### Index configuration #### Custom attribute definition You can add a custom attribute by using the `add_attribute` option or by using a block. ⚠️ When using custom attributes, the gem is not able to detect changes on them. Your record will be pushed to the API even if the custom attribute didn't change. To prevent this behavior, you can create a `will_save_change_to_#{attr_name}?` method. ```ruby class Author < ApplicationRecord include MeiliSearch::Rails meilisearch do attribute :first_name, :last_name attribute :full_name do "#{first_name} #{last_name}" end add_attribute :full_name_reversed end def full_name_reversed "#{last_name} #{first_name}" end def will_save_change_to_full_name? will_save_change_to_first_name? || will_save_change_to_last_name? end def will_save_change_to_full_name_reversed? will_save_change_to_first_name? || will_save_change_to_last_name? end end ``` #### Custom primary key By default, the primary key is based on your record's id. You can change this behavior by specifying the `primary_key:` option. Note that the primary key must have a **unique value**. ```ruby class Book < ActiveRecord::Base include MeiliSearch::Rails meilisearch primary_key: 'ISBN' end ``` #### Conditional indexing You can control if a record must be indexed by using the `if:` or `unless:` options.