meilisearch-rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/Gemfile +30 -0
- data/LICENSE +21 -0
- data/README.md +668 -0
- data/Rakefile +17 -0
- data/lib/meilisearch-rails.rb +921 -0
- data/lib/meilisearch/configuration.rb +15 -0
- data/lib/meilisearch/ms_job.rb +9 -0
- data/lib/meilisearch/pagination.rb +19 -0
- data/lib/meilisearch/pagination/kaminari.rb +40 -0
- data/lib/meilisearch/pagination/will_paginate.rb +19 -0
- data/lib/meilisearch/railtie.rb +11 -0
- data/lib/meilisearch/tasks/meilisearch.rake +19 -0
- data/lib/meilisearch/utilities.rb +48 -0
- data/lib/meilisearch/version.rb +3 -0
- data/meilisearch-rails.gemspec +46 -0
- data/spec/spec_helper.rb +52 -0
- data/spec/utilities_spec.rb +30 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cd9fd3dfd135348e2daea1797697e8b879f08705e2878b3683e59b28d51676c7
|
4
|
+
data.tar.gz: 7226660145964ae88bac72436690aad1a890e76cacd8d4c3fa1e1d3a1d3036e0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 66a1950a5b9bf12469f40053ee01bae86f1379f8a6437de2dff7cc65e55ef64ead442cccc23b39a9d609b4693a1ced987ae51136671fe2d1a53f494fa1ee66dd
|
7
|
+
data.tar.gz: 1e8e5b33d6cb193a432ae09c10f9611ff709a2e9d744fad40e069c7098f39db582b250e8d33288b2beb4ccc72d740a6b9e6f3b439163b6d271e250897e836ea8
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem 'json', '~> 2.5', '>= 2.5.1'
|
4
|
+
gem 'meilisearch', '~> 0.15.3'
|
5
|
+
|
6
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
7
|
+
gem 'rubysl', '~> 2.0', :platform => :rbx
|
8
|
+
end
|
9
|
+
|
10
|
+
group :test do
|
11
|
+
rails_version = ENV["RAILS_VERSION"] || '5.2'
|
12
|
+
gem 'rails', "~> #{rails_version}"
|
13
|
+
gem 'active_model_serializers'
|
14
|
+
if Gem::Version.new(rails_version) >= Gem::Version.new('6.0')
|
15
|
+
gem 'sqlite3', '~> 1.4.0', :platform => [:rbx, :ruby]
|
16
|
+
else
|
17
|
+
gem 'sqlite3', '< 1.4.0', :platform => [:rbx, :ruby]
|
18
|
+
end
|
19
|
+
gem 'rspec', '>= 2.5.0', '< 3.0'
|
20
|
+
gem 'jdbc-sqlite3', :platform => :jruby
|
21
|
+
gem 'activerecord-jdbc-adapter', :platform => :jruby
|
22
|
+
gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby
|
23
|
+
|
24
|
+
sequel_version = ENV['SEQUEL_VERSION'] ? "~> #{ENV['SEQUEL_VERSION']}" : '>= 4.0'
|
25
|
+
gem 'sequel', sequel_version
|
26
|
+
gem 'faker', '~> 2.17'
|
27
|
+
gem 'will_paginate', '>= 2.3.15'
|
28
|
+
gem 'kaminari'
|
29
|
+
gem 'dotenv', '~> 2.7', '>= 2.7.6'
|
30
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 MeiliSearch
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,668 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="https://res.cloudinary.com/meilisearch/image/upload/v1587402338/SDKs/meilisearch_rails.svg" alt="MeiliSearch-Rails" width="200" height="200" />
|
3
|
+
</p>
|
4
|
+
|
5
|
+
<h1 align="center">MeiliSearch Rails</h1>
|
6
|
+
|
7
|
+
<h4 align="center">
|
8
|
+
<a href="https://github.com/meilisearch/MeiliSearch">MeiliSearch</a> |
|
9
|
+
<a href="https://docs.meilisearch.com">Documentation</a> |
|
10
|
+
<a href="https://slack.meilisearch.com">Slack</a> |
|
11
|
+
<a href="https://roadmap.meilisearch.com/tabs/1-under-consideration">Roadmap</a> |
|
12
|
+
<a href="https://www.meilisearch.com">Website</a> |
|
13
|
+
<a href="https://docs.meilisearch.com/faq">FAQ</a>
|
14
|
+
</h4>
|
15
|
+
|
16
|
+
<p align="center">
|
17
|
+
<a href="https://github.com/meilisearch/meilisearch-rails/actions"><img src="https://github.com/meilisearch/meilisearch-rails/workflows/Tests/badge.svg" alt="Test"></a>
|
18
|
+
<a href="https://github.com/meilisearch/meilisearch-rails/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
|
19
|
+
<a href="https://app.bors.tech/repositories/33032"><img src="https://bors.tech/images/badge_small.svg" alt="Bors enabled"></a>
|
20
|
+
</p>
|
21
|
+
|
22
|
+
<p align="center">⚡ The MeiliSearch integration for Ruby on Rails 💎</p>
|
23
|
+
|
24
|
+
**MeiliSearch Rails** is the MeiliSearch integration for Ruby on Rails developers.
|
25
|
+
|
26
|
+
**MeiliSearch** is an open-source search engine. [Discover what MeiliSearch is!](https://github.com/meilisearch/MeiliSearch)
|
27
|
+
|
28
|
+
## Table of Contents <!-- omit in toc -->
|
29
|
+
|
30
|
+
- [📖 Documentation](#-documentation)
|
31
|
+
- [🤖 Compatibility with MeiliSearch](#-compatibility-with-meilisearch)
|
32
|
+
- [🔧 Installation](#-installation)
|
33
|
+
- [🔩 Settings](#-settings)
|
34
|
+
- [🔍 Custom search](#-custom-search)
|
35
|
+
- [🪛 Options](#-options)
|
36
|
+
- [MeiliSearch configuration & environment](#meilisearch-configuration-&-environment)
|
37
|
+
- [Custom index_uid](#custom-index_uid)
|
38
|
+
- [Per-environment index_uid](#per-environment-index_uid)
|
39
|
+
- [Index configuration](#index-configuration)
|
40
|
+
- [Custom attribute definition](#custom-attribute-definition)
|
41
|
+
- [Custom primary key](#custom-primary-key)
|
42
|
+
- [Conditional indexing](#conditional-indexing)
|
43
|
+
- [Target multiple indexes](#target-multiple-indexes)
|
44
|
+
- [Share a single index](#share-a-single-index)
|
45
|
+
- [Queues & background jobs](#queues-&-background-jobs)
|
46
|
+
- [Relations](#relations)
|
47
|
+
- [Sanitize attributes](#sanitize-attributes)
|
48
|
+
- [UTF-8 encoding](#utf-8-encoding)
|
49
|
+
- [Manual operations](#manual-operations)
|
50
|
+
- [Indexing & deletion](#indexing-&-deletion)
|
51
|
+
- [Access the underlying index object](#access-the-underlying-index-object)
|
52
|
+
- [Development & testing](#development-&-testing)
|
53
|
+
- [Exceptions](#exceptions)
|
54
|
+
- [Testing](#testing)
|
55
|
+
- [Synchronous testing](#synchronous-testing)
|
56
|
+
- [Disable auto-indexing & auto-removal](#disable-auto-indexing-&-auto-removal)
|
57
|
+
- [⚙️ Development Workflow and Contributing](#️-development-workflow-and-contributing)
|
58
|
+
- [👏 Credits](#-credits)
|
59
|
+
|
60
|
+
## 📖 Documentation
|
61
|
+
|
62
|
+
The whole usage of this gem is detailed in this README.
|
63
|
+
|
64
|
+
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/).
|
65
|
+
|
66
|
+
## 🤖 Compatibility with MeiliSearch
|
67
|
+
|
68
|
+
This package only guarantees the compatibility with the [version v0.20.0 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.20.0).
|
69
|
+
|
70
|
+
## 🔧 Installation
|
71
|
+
|
72
|
+
This package requires Ruby version 2.6.0 or later and Rails 5.2 or later.
|
73
|
+
|
74
|
+
With `gem` in command line:
|
75
|
+
```bash
|
76
|
+
gem install meilisearch-rails
|
77
|
+
```
|
78
|
+
|
79
|
+
In your `Gemfile` with [bundler](https://bundler.io/):
|
80
|
+
```ruby
|
81
|
+
source 'https://rubygems.org'
|
82
|
+
|
83
|
+
gem 'meilisearch-rails'
|
84
|
+
```
|
85
|
+
|
86
|
+
### Run MeiliSearch <!-- omit in toc -->
|
87
|
+
|
88
|
+
There are many easy ways to [download and run a MeiliSearch instance](https://docs.meilisearch.com/reference/features/installation.html#download-and-launch).
|
89
|
+
|
90
|
+
For example, if you use Docker:
|
91
|
+
|
92
|
+
```bash
|
93
|
+
docker pull getmeili/meilisearch:latest # Fetch the latest version of MeiliSearch image from Docker Hub
|
94
|
+
docker run -it --rm -p 7700:7700 getmeili/meilisearch:latest ./meilisearch --master-key=masterKey
|
95
|
+
```
|
96
|
+
|
97
|
+
NB: you can also download MeiliSearch from **Homebrew** or **APT**.
|
98
|
+
|
99
|
+
## 🚀 Getting Started
|
100
|
+
|
101
|
+
#### Configuration <!-- omit in toc -->
|
102
|
+
|
103
|
+
Create a new file `config/initializers/meilisearch.rb` to setup your `MEILISEARCH_HOST` and `MEILISEARCH_API_KEY`
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
MeiliSearch.configuration = {
|
107
|
+
meilisearch_host: 'YourMeiliSearchHost',
|
108
|
+
meilisearch_api_key: 'YourMeiliSearchAPIKey',
|
109
|
+
}
|
110
|
+
```
|
111
|
+
|
112
|
+
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).
|
113
|
+
|
114
|
+
#### Add documents <!-- omit in toc -->
|
115
|
+
|
116
|
+
The following code will create a `Book` index and add search capabilities to your `Book` model.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
class Book < ActiveRecord::Base
|
120
|
+
include MeiliSearch
|
121
|
+
|
122
|
+
meilisearch do
|
123
|
+
attribute :title, :author # only the attributes 'title', and 'author' will be sent to MeiliSearch
|
124
|
+
# all attributes will be sent to MeiliSearch if block is left empty
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
#### Basic Backend Search <!-- omit in toc -->
|
130
|
+
|
131
|
+
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)
|
132
|
+
|
133
|
+
Search returns ORM-compliant objects reloaded from your database.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
# MeiliSearch is typo-tolerant:
|
137
|
+
hits = Book.search('harry pottre')
|
138
|
+
hits.each do |hit|
|
139
|
+
puts hit.title
|
140
|
+
puts hit.author
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
#### Backend Pagination <!-- omit in toc -->
|
145
|
+
|
146
|
+
We support both [kaminari](https://github.com/amatsuda/kaminari) and [will_paginate](https://github.com/mislav/will_paginate).
|
147
|
+
|
148
|
+
Specify the `:pagination_backend` in the configuration file:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
MeiliSearch.configuration = {
|
152
|
+
meilisearch_host: 'YourMeiliSearchHost',
|
153
|
+
meilisearch_api_key: 'YourMeiliSearchAPIKey',
|
154
|
+
pagination_backend: :kaminari #:will_paginate
|
155
|
+
}
|
156
|
+
```
|
157
|
+
|
158
|
+
Then, as soon as you use the `search` method, the returning results will be paginated:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
# controller
|
162
|
+
@hits = Book.search('harry potter')
|
163
|
+
|
164
|
+
# views
|
165
|
+
<% @hits.each do |hit| %>
|
166
|
+
<%= hit.title %>
|
167
|
+
<%= hit.author %>
|
168
|
+
<% end %>
|
169
|
+
|
170
|
+
<%= paginate @hits %> # if using kaminari
|
171
|
+
|
172
|
+
<%= will_paginate @hits %> # if using will_paginate
|
173
|
+
```
|
174
|
+
|
175
|
+
The **number of hits per page defaults to 20**, you can customize it by adding the `hitsPerPage` parameter to your search:
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
Book.search('harry potter', hitsPerPage: 10)
|
179
|
+
```
|
180
|
+
|
181
|
+
## ⚙️ Settings
|
182
|
+
|
183
|
+
You can configure the index settings by adding them inside the `meilisearch` block as shown below:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
class Book < ApplicationRecord
|
187
|
+
include MeiliSearch
|
188
|
+
|
189
|
+
meilisearch do
|
190
|
+
searchableAttributes ['title', 'author', 'publisher', 'description']
|
191
|
+
attributesForFaceting ['genre']
|
192
|
+
rankingRules [
|
193
|
+
"proximity",
|
194
|
+
"typo",
|
195
|
+
"words",
|
196
|
+
"attribute",
|
197
|
+
"wordsPosition",
|
198
|
+
"exactness",
|
199
|
+
"desc(publication_year)"
|
200
|
+
]
|
201
|
+
synonyms nyc: ['new york']
|
202
|
+
// The following parameters are applied when calling the search() method:
|
203
|
+
attributesToHighlight ['*']
|
204
|
+
attributesToCrop ['description']
|
205
|
+
cropLength 10
|
206
|
+
end
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
Check the dedicated section of the documentation, for more information on the [settings](https://docs.meilisearch.com/reference/features/settings.html).
|
211
|
+
|
212
|
+
## 🔍 Custom search
|
213
|
+
|
214
|
+
All the supported options are described in the [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html) section of the documentation.
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
Book.search('Harry', { filters: 'author = J. K. Rowling' })
|
218
|
+
```
|
219
|
+
👉 Don't forget that `attributesToHighlight`, `attributesToCrop`, and `cropLength` can be set up in the `meilisearch` block of your model.
|
220
|
+
|
221
|
+
## 🪛 Options
|
222
|
+
|
223
|
+
### MeiliSearch configuration & environment
|
224
|
+
|
225
|
+
#### Custom index_uid
|
226
|
+
|
227
|
+
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.
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
class Book < ActiveRecord::Base
|
231
|
+
include MeiliSearch
|
232
|
+
meilisearch :index_uid => 'MyCustomUID' do
|
233
|
+
end
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
#### Index UID according to the environment
|
238
|
+
|
239
|
+
You can suffix the index UID with the current Rails environment using the following option:
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
class Book < ActiveRecord::Base
|
243
|
+
include MeiliSearch
|
244
|
+
meilisearch per_environment: true do # The index UID will be "Book_#{Rails.env}"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
```
|
248
|
+
|
249
|
+
### Index configuration
|
250
|
+
|
251
|
+
#### Custom attribute definition
|
252
|
+
|
253
|
+
You can add a custom attribute by using the `add_attribute` option or by using a block.
|
254
|
+
|
255
|
+
⚠️ 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.
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
class Author < ApplicationRecord
|
259
|
+
include MeiliSearch
|
260
|
+
|
261
|
+
meilisearch do
|
262
|
+
attribute :first_name, :last_name
|
263
|
+
attribute :full_name do
|
264
|
+
'#{first_name} #{last_name}'
|
265
|
+
end
|
266
|
+
add_attribute :full_name_reversed
|
267
|
+
end
|
268
|
+
|
269
|
+
def full_name_reversed
|
270
|
+
'#{last_name} #{first_name}'
|
271
|
+
end
|
272
|
+
|
273
|
+
def will_save_change_to_full_name?
|
274
|
+
will_save_change_to_first_name? || will_save_change_to_last_name?
|
275
|
+
end
|
276
|
+
|
277
|
+
def will_save_change_to_full_name_reversed?
|
278
|
+
will_save_change_to_first_name? || will_save_change_to_last_name?
|
279
|
+
end
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
283
|
+
#### Custom primary key
|
284
|
+
|
285
|
+
By default, the `primary key` is based on your record's id. You can change this behavior specifying the `:primary_key` option.
|
286
|
+
|
287
|
+
Note that the primary key must have a **unique value**.
|
288
|
+
|
289
|
+
```ruby
|
290
|
+
class Book < ActiveRecord::Base
|
291
|
+
include MeiliSearch
|
292
|
+
meilisearch :primary_key => 'ISBN' do
|
293
|
+
end
|
294
|
+
end
|
295
|
+
```
|
296
|
+
#### Conditional indexing
|
297
|
+
|
298
|
+
You can control if a record must be indexed by using the `:if` or `:unless` options.<br>
|
299
|
+
As soon as you use those constraints, `add_documents` and `delete_documents` calls will be performed in order to keep the index synced with the DB. To prevent this behavior, you can create a `will_save_change_to_#{attr_name}?` method.
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
class Book < ActiveRecord::Base
|
303
|
+
include MeiliSearch
|
304
|
+
|
305
|
+
meilisearch :if published?, :unless premium? do
|
306
|
+
end
|
307
|
+
|
308
|
+
def published?
|
309
|
+
# [...]
|
310
|
+
end
|
311
|
+
|
312
|
+
def premium?
|
313
|
+
# [...]
|
314
|
+
end
|
315
|
+
|
316
|
+
def will_save_change_to_published?
|
317
|
+
# return true only if you know that the 'published' state changed
|
318
|
+
end
|
319
|
+
end
|
320
|
+
```
|
321
|
+
##### Target multiple indexes
|
322
|
+
|
323
|
+
You can index a record in several indexes using the `add_index` option:
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
class Book < ActiveRecord::Base
|
327
|
+
|
328
|
+
include MeiliSearch
|
329
|
+
|
330
|
+
PUBLIC_INDEX_UID = 'Books'
|
331
|
+
SECURED_INDEX_UID = 'PrivateBooks'
|
332
|
+
|
333
|
+
# store all books in index 'SECURED_INDEX_UID'
|
334
|
+
meilisearch index_uid: SECURED_INDEX_UID do
|
335
|
+
searchableAttributes [:title, :author]
|
336
|
+
|
337
|
+
# store all 'public' (released and not premium) books in index 'PUBLIC_INDEX_UID'
|
338
|
+
add_index PUBLIC_INDEX_UID, if: :public? do
|
339
|
+
searchableAttributes [:title, :author]
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
private
|
344
|
+
def public?
|
345
|
+
released && !premium
|
346
|
+
end
|
347
|
+
end
|
348
|
+
```
|
349
|
+
|
350
|
+
#### Share a single index
|
351
|
+
|
352
|
+
You may want to share an index between several models. You'll need to ensure you don't have any conflict with the `primary_key` of the models involved.
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
class Cat < ActiveRecord::Base
|
356
|
+
include MeiliSearch
|
357
|
+
|
358
|
+
meilisearch index_uid: 'Animals', primary_key: :ms_id do
|
359
|
+
end
|
360
|
+
|
361
|
+
private
|
362
|
+
def ms_id
|
363
|
+
"cat_#{primary_key}" # ensure the cats & dogs primary_keys are not conflicting
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
class Dog < ActiveRecord::Base
|
368
|
+
include MeiliSearch
|
369
|
+
|
370
|
+
meilisearch index_uid: 'Animals', primary_key: :ms_id do
|
371
|
+
end
|
372
|
+
|
373
|
+
private
|
374
|
+
def ms_id
|
375
|
+
"dog_#{primary_key}" # ensure the cats & dogs primary_keys are not conflicting
|
376
|
+
end
|
377
|
+
end
|
378
|
+
```
|
379
|
+
|
380
|
+
#### Queues & background jobs
|
381
|
+
|
382
|
+
You can configure the auto-indexing & auto-removal process to use a queue to perform those operations in background. ActiveJob queues are used by default but you can define your own queuing mechanism:
|
383
|
+
|
384
|
+
```ruby
|
385
|
+
class Book < ActiveRecord::Base
|
386
|
+
include MeiliSearch
|
387
|
+
|
388
|
+
meilisearch enqueue: true do # ActiveJob will be triggered using a `meilisearch` queue
|
389
|
+
end
|
390
|
+
end
|
391
|
+
```
|
392
|
+
|
393
|
+
🤔 If you are performing updates and deletions in the background, a record deletion can be committed to your database prior to the job actually executing. Thus if you were to load the record to remove it from the database then your `ActiveRecord#find` will fail with a `RecordNotFound`.
|
394
|
+
|
395
|
+
In this case you can bypass loading the record from **ActiveRecord** and just communicate with the index directly.
|
396
|
+
|
397
|
+
```ruby
|
398
|
+
class MyActiveJob < ApplicationJob
|
399
|
+
def perform(id, remove)
|
400
|
+
if remove
|
401
|
+
# the record has likely already been removed from your database so we cannot
|
402
|
+
# use ActiveRecord#find to load it
|
403
|
+
# We access the underlying MeiliSearch index object
|
404
|
+
Book.index.delete_document(id)
|
405
|
+
else
|
406
|
+
# the record should be present
|
407
|
+
c = Book.find(id)
|
408
|
+
c.index!
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
```
|
413
|
+
|
414
|
+
With [**Sidekiq**](https://github.com/mperham/sidekiq):
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
class Book < ActiveRecord::Base
|
418
|
+
include MeiliSearch
|
419
|
+
|
420
|
+
meilisearch enqueue: :trigger_sidekiq_worker do
|
421
|
+
attribute :title, :author, :description
|
422
|
+
end
|
423
|
+
|
424
|
+
def self.trigger_sidekiq_worker(record, remove)
|
425
|
+
MySidekiqWorker.perform_async(record.id, remove)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
class MySidekiqWorker
|
430
|
+
def perform(id, remove)
|
431
|
+
if remove
|
432
|
+
# the record has likely already been removed from your database so we cannot
|
433
|
+
# use ActiveRecord#find to load it
|
434
|
+
# We access the underlying MeiliSearch index object
|
435
|
+
index = Book.index.delete_document(id)
|
436
|
+
else
|
437
|
+
# the record should be present
|
438
|
+
c = Contact.find(id)
|
439
|
+
c.index!
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
```
|
444
|
+
|
445
|
+
With [**DelayedJob**](https://github.com/collectiveidea/delayed_job):
|
446
|
+
|
447
|
+
```ruby
|
448
|
+
class Book < ActiveRecord::Base
|
449
|
+
include MeiliSearch
|
450
|
+
|
451
|
+
meilisearch enqueue: :trigger_delayed_job do
|
452
|
+
attribute :title, :author, :description
|
453
|
+
end
|
454
|
+
|
455
|
+
def self.trigger_delayed_job(record, remove)
|
456
|
+
if remove
|
457
|
+
record.delay.remove_from_index!
|
458
|
+
else
|
459
|
+
record.delay.index!
|
460
|
+
end
|
461
|
+
end
|
462
|
+
end
|
463
|
+
```
|
464
|
+
|
465
|
+
#### Relations
|
466
|
+
|
467
|
+
Extend a change to a related record.
|
468
|
+
|
469
|
+
**With Active Record**, you'll need to use `touch` and `after_touch`.
|
470
|
+
|
471
|
+
```ruby
|
472
|
+
class Author < ActiveRecord::Base
|
473
|
+
include MeiliSearch
|
474
|
+
|
475
|
+
has_many :books
|
476
|
+
# If your association uses belongs_to
|
477
|
+
# - use `touch: true`
|
478
|
+
# - do not define an `after_save` hook
|
479
|
+
after_save { books.each(&:touch) }
|
480
|
+
end
|
481
|
+
|
482
|
+
class Book < ActiveRecord::Base
|
483
|
+
include MeiliSearch
|
484
|
+
|
485
|
+
belongs_to :author
|
486
|
+
after_touch :index!
|
487
|
+
|
488
|
+
meilisearch do
|
489
|
+
attribute :title, :description, :publisher
|
490
|
+
attribute :author do
|
491
|
+
author.name
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
```
|
496
|
+
|
497
|
+
With **Sequel**, you can use the `touch` plugin to propagate changes.
|
498
|
+
|
499
|
+
```ruby
|
500
|
+
# app/models/author.rb
|
501
|
+
class Author < Sequel::Model
|
502
|
+
include MeiliSearch
|
503
|
+
|
504
|
+
one_to_many :books
|
505
|
+
|
506
|
+
plugin :timestamps
|
507
|
+
# Can't use the associations since it won't trigger the after_save
|
508
|
+
plugin :touch
|
509
|
+
|
510
|
+
# Define the associations that need to be touched here
|
511
|
+
# Less performant, but allows for the after_save hook to be triggered
|
512
|
+
def touch_associations
|
513
|
+
apps.map(&:touch)
|
514
|
+
end
|
515
|
+
|
516
|
+
def touch
|
517
|
+
super
|
518
|
+
touch_associations
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
# app/models/book.rb
|
523
|
+
class Book < Sequel::Model
|
524
|
+
include MeiliSearch
|
525
|
+
|
526
|
+
many_to_one :author
|
527
|
+
after_touch :index!
|
528
|
+
|
529
|
+
plugin :timestamps
|
530
|
+
plugin :touch
|
531
|
+
|
532
|
+
meilisearch do
|
533
|
+
attribute :title, :description, :publisher
|
534
|
+
attribute :author do
|
535
|
+
author.name
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
```
|
540
|
+
|
541
|
+
#### Sanitize attributes
|
542
|
+
|
543
|
+
You can strip all HTML tags from your attributes with the `sanitize` option.
|
544
|
+
|
545
|
+
```ruby
|
546
|
+
class Book < ActiveRecord::Base
|
547
|
+
include MeiliSearch
|
548
|
+
|
549
|
+
meilisearch :sanitize => true do
|
550
|
+
end
|
551
|
+
end
|
552
|
+
```
|
553
|
+
|
554
|
+
#### UTF-8 encoding
|
555
|
+
|
556
|
+
You can force the UTF-8 encoding of all your attributes using the `force_utf8_encoding` option.
|
557
|
+
|
558
|
+
```ruby
|
559
|
+
class Book < ActiveRecord::Base
|
560
|
+
include MeiliSearch
|
561
|
+
|
562
|
+
meilisearch :force_utf8_encoding => true do
|
563
|
+
end
|
564
|
+
end
|
565
|
+
```
|
566
|
+
|
567
|
+
### Manual operations
|
568
|
+
|
569
|
+
#### Indexing & deletion
|
570
|
+
|
571
|
+
You can manually index a record by using the `index!` instance method and remove it by using the `remove_from_index!` instance method
|
572
|
+
|
573
|
+
```ruby
|
574
|
+
book = Book.create!(title: 'The Little Prince', author: 'Antoine de Saint-Exupéry')
|
575
|
+
book.index!
|
576
|
+
book.remove_from_index!
|
577
|
+
book.destroy!
|
578
|
+
```
|
579
|
+
|
580
|
+
To reindex all your records, use the `reindex!` class method:
|
581
|
+
|
582
|
+
```ruby
|
583
|
+
Book.reindex!
|
584
|
+
|
585
|
+
# You can also index a subset of your records
|
586
|
+
Book.where('updated_at > ?', 10.minutes.ago).reindex!
|
587
|
+
```
|
588
|
+
|
589
|
+
To delete all your records, use the `clear_index!` class method:
|
590
|
+
|
591
|
+
```ruby
|
592
|
+
Book.clear_index!
|
593
|
+
```
|
594
|
+
|
595
|
+
#### Access the underlying index object
|
596
|
+
|
597
|
+
To access the index object and use the [Ruby SDK](https://github.com/meilisearch/meilisearch-ruby) methods for an index, call the `index` class method:
|
598
|
+
|
599
|
+
```ruby
|
600
|
+
index = Book.index
|
601
|
+
# index.get_settings, index.number_of_documents
|
602
|
+
```
|
603
|
+
|
604
|
+
### Development & testing
|
605
|
+
|
606
|
+
|
607
|
+
#### Exceptions
|
608
|
+
|
609
|
+
You can disable exceptions that could be raised while trying to reach MeiliSearch's API by using the `raise_on_failure` option:
|
610
|
+
|
611
|
+
```ruby
|
612
|
+
class Book < ActiveRecord::Base
|
613
|
+
include MeiliSearch
|
614
|
+
|
615
|
+
# only raise exceptions in development environment
|
616
|
+
meilisearch :raise_on_failure => Rails.env.development? do
|
617
|
+
end
|
618
|
+
end
|
619
|
+
```
|
620
|
+
|
621
|
+
#### Testing
|
622
|
+
##### Synchronous testing
|
623
|
+
You can force indexing and removing to be synchronous by setting the following option:
|
624
|
+
|
625
|
+
```ruby
|
626
|
+
class Book < ActiveRecord::Base
|
627
|
+
include MeiliSearch
|
628
|
+
|
629
|
+
meilisearch synchronous: true do
|
630
|
+
end
|
631
|
+
end
|
632
|
+
```
|
633
|
+
🚨 This is only recommended for testing purposes, the gem will call the `wait_for_pending_update` method that will stop your code execution until the asynchronous task has been processed by MeilSearch.
|
634
|
+
|
635
|
+
##### Disable auto-indexing & auto-removal
|
636
|
+
|
637
|
+
You can disable auto-indexing and auto-removing setting the following options:
|
638
|
+
|
639
|
+
```ruby
|
640
|
+
class Book < ActiveRecord::Base
|
641
|
+
include MeiliSearch
|
642
|
+
|
643
|
+
meilisearch auto_index: false, auto_remove: false do
|
644
|
+
end
|
645
|
+
end
|
646
|
+
```
|
647
|
+
|
648
|
+
You can temporarily disable auto-indexing using the without_auto_index scope:
|
649
|
+
|
650
|
+
```ruby
|
651
|
+
Book.without_auto_index do
|
652
|
+
1.upto(10000) { Book.create! attributes } # inside this block, auto indexing task will not run.
|
653
|
+
end
|
654
|
+
```
|
655
|
+
|
656
|
+
## ⚙️ Development workflow & contributing
|
657
|
+
|
658
|
+
Any new contribution is more than welcome in this project!
|
659
|
+
|
660
|
+
If you want to know more about the development workflow or want to contribute, please visit our [contributing guidelines](/CONTRIBUTING.md) for detailed instructions!
|
661
|
+
|
662
|
+
## 👏 Credits
|
663
|
+
|
664
|
+
The provided features and the code base is inspired by [algoliasearch-rails](https://github.com/algolia/algoliasearch-rails/).
|
665
|
+
|
666
|
+
<hr>
|
667
|
+
|
668
|
+
**MeiliSearch** provides and maintains many **SDKs and Integration tools** like this one. We want to provide everyone with an **amazing search experience for any kind of project**. If you want to contribute, make suggestions, or just know what's going on right now, visit us in the [integration-guides](https://github.com/meilisearch/integration-guides) repository.
|