meilisearch-rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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.