meilisearch-rails 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +75 -52
- data/lib/meilisearch-rails.rb +18 -19
- data/lib/meilisearch/pagination/kaminari.rb +2 -2
- data/lib/meilisearch/version.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/utilities_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1562941b9f5cf4cb5a13085147f5b9b9ba1b3ea04587f6d1c520239ae5362236
|
4
|
+
data.tar.gz: 57106ef19a839131d89e45bbb3d01f6aeef6fca623f3d803ade4f63282c2221d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d33ff75ad9c5dc9eeab0c602bdfc5fa8f80b1d14d3a025105cf04c7c2e644a1309e68cbff56452eeea5c1801e13fc58d11f8dd529b02bd6ac14e3baf4c30d20
|
7
|
+
data.tar.gz: 02720ef33a1a0da9cc309f04c24129c87b9f1d885e9d8ff4386ba0873f1aec14e88373bbabe8eae279627a76e573046d4ae445ac1837efffda39b7a458e33fa3
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -126,6 +126,8 @@ class Book < ActiveRecord::Base
|
|
126
126
|
end
|
127
127
|
```
|
128
128
|
|
129
|
+
⚠️ Note that even if you want to use all the default options, you must declare an empty `meilisearch` block in your model.
|
130
|
+
|
129
131
|
#### Basic Backend Search <!-- omit in toc -->
|
130
132
|
|
131
133
|
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)
|
@@ -143,15 +145,18 @@ end
|
|
143
145
|
|
144
146
|
#### Backend Pagination <!-- omit in toc -->
|
145
147
|
|
146
|
-
|
148
|
+
This gem supports:
|
149
|
+
- [kaminari](https://github.com/amatsuda/kaminari)
|
150
|
+
- [pagy](https://github.com/ddnexus/pagy)
|
151
|
+
- [will_paginate](https://github.com/mislav/will_paginate).
|
147
152
|
|
148
153
|
Specify the `:pagination_backend` in the configuration file:
|
149
154
|
|
150
155
|
```ruby
|
151
156
|
MeiliSearch.configuration = {
|
152
|
-
|
153
|
-
|
154
|
-
|
157
|
+
meilisearch_host: 'YourMeiliSearchHost',
|
158
|
+
meilisearch_api_key: 'YourMeiliSearchAPIKey',
|
159
|
+
pagination_backend: :kaminari #:will_paginate
|
155
160
|
}
|
156
161
|
```
|
157
162
|
|
@@ -187,22 +192,23 @@ class Book < ApplicationRecord
|
|
187
192
|
include MeiliSearch
|
188
193
|
|
189
194
|
meilisearch do
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
195
|
+
searchable_attributes [:title, :author, :publisher, :description]
|
196
|
+
attributes_for_faceting [:genre]
|
197
|
+
ranking_rules [
|
198
|
+
'proximity',
|
199
|
+
'typo',
|
200
|
+
'words',
|
201
|
+
'attribute',
|
202
|
+
'wordsPosition',
|
203
|
+
'exactness',
|
204
|
+
'desc(publication_year)'
|
200
205
|
]
|
201
206
|
synonyms nyc: ['new york']
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
207
|
+
|
208
|
+
# The following parameters are applied when calling the search() method:
|
209
|
+
attributes_to_highlight ['*']
|
210
|
+
attributes_to_crop [:description]
|
211
|
+
crop_length 10
|
206
212
|
end
|
207
213
|
end
|
208
214
|
```
|
@@ -214,9 +220,10 @@ Check the dedicated section of the documentation, for more information on the [s
|
|
214
220
|
All the supported options are described in the [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html) section of the documentation.
|
215
221
|
|
216
222
|
```ruby
|
217
|
-
Book.search('Harry',
|
223
|
+
Book.search('Harry', filters: 'author = J. K. Rowling')
|
218
224
|
```
|
219
|
-
👉 Don't forget that `
|
225
|
+
👉 Don't forget that `attributes_to_highlight`, `attributes_to_crop`, and
|
226
|
+
`crop_length` can be set up in the `meilisearch` block of your model.
|
220
227
|
|
221
228
|
## 🪛 Options
|
222
229
|
|
@@ -224,12 +231,13 @@ Book.search('Harry', { filters: 'author = J. K. Rowling' })
|
|
224
231
|
|
225
232
|
#### Custom index_uid
|
226
233
|
|
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
|
234
|
+
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
235
|
|
229
236
|
```ruby
|
230
237
|
class Book < ActiveRecord::Base
|
231
238
|
include MeiliSearch
|
232
|
-
|
239
|
+
|
240
|
+
meilisearch index_uid: 'MyCustomUID' do
|
233
241
|
end
|
234
242
|
end
|
235
243
|
```
|
@@ -241,6 +249,7 @@ You can suffix the index UID with the current Rails environment using the follow
|
|
241
249
|
```ruby
|
242
250
|
class Book < ActiveRecord::Base
|
243
251
|
include MeiliSearch
|
252
|
+
|
244
253
|
meilisearch per_environment: true do # The index UID will be "Book_#{Rails.env}"
|
245
254
|
end
|
246
255
|
end
|
@@ -282,27 +291,28 @@ end
|
|
282
291
|
|
283
292
|
#### Custom primary key
|
284
293
|
|
285
|
-
By default, the
|
294
|
+
By default, the primary key is based on your record's id. You can change this behavior by specifying the `primary_key:` option.
|
286
295
|
|
287
296
|
Note that the primary key must have a **unique value**.
|
288
297
|
|
289
298
|
```ruby
|
290
299
|
class Book < ActiveRecord::Base
|
291
300
|
include MeiliSearch
|
292
|
-
|
301
|
+
|
302
|
+
meilisearch primary_key: 'ISBN' do
|
293
303
|
end
|
294
304
|
end
|
295
305
|
```
|
296
306
|
#### Conditional indexing
|
297
307
|
|
298
|
-
You can control if a record must be indexed by using the
|
308
|
+
You can control if a record must be indexed by using the `if:` or `unless:` options.<br>
|
299
309
|
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
310
|
|
301
311
|
```ruby
|
302
312
|
class Book < ActiveRecord::Base
|
303
313
|
include MeiliSearch
|
304
314
|
|
305
|
-
meilisearch :
|
315
|
+
meilisearch if: :published?, unless: :premium? do
|
306
316
|
end
|
307
317
|
|
308
318
|
def published?
|
@@ -314,7 +324,7 @@ class Book < ActiveRecord::Base
|
|
314
324
|
end
|
315
325
|
|
316
326
|
def will_save_change_to_published?
|
317
|
-
|
327
|
+
# return true only if you know that the 'published' state changed
|
318
328
|
end
|
319
329
|
end
|
320
330
|
```
|
@@ -324,7 +334,6 @@ You can index a record in several indexes using the `add_index` option:
|
|
324
334
|
|
325
335
|
```ruby
|
326
336
|
class Book < ActiveRecord::Base
|
327
|
-
|
328
337
|
include MeiliSearch
|
329
338
|
|
330
339
|
PUBLIC_INDEX_UID = 'Books'
|
@@ -332,17 +341,17 @@ class Book < ActiveRecord::Base
|
|
332
341
|
|
333
342
|
# store all books in index 'SECURED_INDEX_UID'
|
334
343
|
meilisearch index_uid: SECURED_INDEX_UID do
|
335
|
-
|
344
|
+
searchable_attributes [:title, :author]
|
336
345
|
|
337
346
|
# store all 'public' (released and not premium) books in index 'PUBLIC_INDEX_UID'
|
338
347
|
add_index PUBLIC_INDEX_UID, if: :public? do
|
339
|
-
|
348
|
+
searchable_attributes [:title, :author]
|
340
349
|
end
|
341
350
|
end
|
342
351
|
|
343
352
|
private
|
344
353
|
def public?
|
345
|
-
released && !premium
|
354
|
+
released? && !premium?
|
346
355
|
end
|
347
356
|
end
|
348
357
|
```
|
@@ -394,18 +403,31 @@ end
|
|
394
403
|
|
395
404
|
In this case you can bypass loading the record from **ActiveRecord** and just communicate with the index directly.
|
396
405
|
|
406
|
+
With **ActiveJob**:
|
407
|
+
|
397
408
|
```ruby
|
409
|
+
class Book < ActiveRecord::Base
|
410
|
+
include MeiliSearch
|
411
|
+
|
412
|
+
meilisearch enqueue: :trigger_job do
|
413
|
+
attribute :title, :author, :description
|
414
|
+
end
|
415
|
+
|
416
|
+
def self.trigger_job(record, remove)
|
417
|
+
MyActiveJob.perform_later(record.id, remove)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
398
421
|
class MyActiveJob < ApplicationJob
|
399
422
|
def perform(id, remove)
|
400
423
|
if remove
|
401
|
-
#
|
402
|
-
# use ActiveRecord#find to load it
|
403
|
-
# We access the underlying MeiliSearch index object
|
424
|
+
# The record has likely already been removed from your database so we cannot
|
425
|
+
# use ActiveRecord#find to load it.
|
426
|
+
# We access the underlying MeiliSearch index object.
|
404
427
|
Book.index.delete_document(id)
|
405
428
|
else
|
406
|
-
#
|
407
|
-
|
408
|
-
c.index!
|
429
|
+
# The record should be present.
|
430
|
+
Book.find(id).index!
|
409
431
|
end
|
410
432
|
end
|
411
433
|
end
|
@@ -429,14 +451,13 @@ end
|
|
429
451
|
class MySidekiqWorker
|
430
452
|
def perform(id, remove)
|
431
453
|
if remove
|
432
|
-
#
|
433
|
-
# use ActiveRecord#find to load it
|
434
|
-
# We access the underlying MeiliSearch index object
|
435
|
-
|
454
|
+
# The record has likely already been removed from your database so we cannot
|
455
|
+
# use ActiveRecord#find to load it.
|
456
|
+
# We access the underlying MeiliSearch index object.
|
457
|
+
Book.index.delete_document(id)
|
436
458
|
else
|
437
|
-
#
|
438
|
-
|
439
|
-
c.index!
|
459
|
+
# The record should be present.
|
460
|
+
Book.find(id).index!
|
440
461
|
end
|
441
462
|
end
|
442
463
|
end
|
@@ -466,7 +487,7 @@ end
|
|
466
487
|
|
467
488
|
Extend a change to a related record.
|
468
489
|
|
469
|
-
**With
|
490
|
+
**With ActiveRecord**, you'll need to use `touch` and `after_touch`.
|
470
491
|
|
471
492
|
```ruby
|
472
493
|
class Author < ActiveRecord::Base
|
@@ -546,7 +567,7 @@ You can strip all HTML tags from your attributes with the `sanitize` option.
|
|
546
567
|
class Book < ActiveRecord::Base
|
547
568
|
include MeiliSearch
|
548
569
|
|
549
|
-
meilisearch :
|
570
|
+
meilisearch sanitize: true do
|
550
571
|
end
|
551
572
|
end
|
552
573
|
```
|
@@ -559,7 +580,7 @@ You can force the UTF-8 encoding of all your attributes using the `force_utf8_en
|
|
559
580
|
class Book < ActiveRecord::Base
|
560
581
|
include MeiliSearch
|
561
582
|
|
562
|
-
meilisearch :
|
583
|
+
meilisearch force_utf8_encoding: true do
|
563
584
|
end
|
564
585
|
end
|
565
586
|
```
|
@@ -568,7 +589,7 @@ end
|
|
568
589
|
|
569
590
|
#### Indexing & deletion
|
570
591
|
|
571
|
-
You can manually index a record by using the `index!` instance method and remove it by using the `remove_from_index!` instance method
|
592
|
+
You can manually index a record by using the `index!` instance method and remove it by using the `remove_from_index!` instance method.
|
572
593
|
|
573
594
|
```ruby
|
574
595
|
book = Book.create!(title: 'The Little Prince', author: 'Antoine de Saint-Exupéry')
|
@@ -603,7 +624,6 @@ index = Book.index
|
|
603
624
|
|
604
625
|
### Development & testing
|
605
626
|
|
606
|
-
|
607
627
|
#### Exceptions
|
608
628
|
|
609
629
|
You can disable exceptions that could be raised while trying to reach MeiliSearch's API by using the `raise_on_failure` option:
|
@@ -612,14 +632,16 @@ You can disable exceptions that could be raised while trying to reach MeiliSearc
|
|
612
632
|
class Book < ActiveRecord::Base
|
613
633
|
include MeiliSearch
|
614
634
|
|
615
|
-
#
|
616
|
-
meilisearch :
|
635
|
+
# Only raise exceptions in development environment.
|
636
|
+
meilisearch raise_on_failure: Rails.env.development? do
|
617
637
|
end
|
618
638
|
end
|
619
639
|
```
|
620
640
|
|
621
641
|
#### Testing
|
642
|
+
|
622
643
|
##### Synchronous testing
|
644
|
+
|
623
645
|
You can force indexing and removing to be synchronous by setting the following option:
|
624
646
|
|
625
647
|
```ruby
|
@@ -649,7 +671,8 @@ You can temporarily disable auto-indexing using the without_auto_index scope:
|
|
649
671
|
|
650
672
|
```ruby
|
651
673
|
Book.without_auto_index do
|
652
|
-
|
674
|
+
# Inside this block, auto indexing task will not run.
|
675
|
+
1.upto(10000) { Book.create! attributes }
|
653
676
|
end
|
654
677
|
```
|
655
678
|
|
data/lib/meilisearch-rails.rb
CHANGED
@@ -52,16 +52,25 @@ module MeiliSearch
|
|
52
52
|
|
53
53
|
# MeiliSearch settings
|
54
54
|
OPTIONS = [
|
55
|
-
:searchableAttributes,
|
56
|
-
:
|
55
|
+
:searchableAttributes,
|
56
|
+
:attributesForFaceting,
|
57
|
+
:displayedAttributes,
|
58
|
+
:distinctAttribute,
|
59
|
+
:synonyms,
|
60
|
+
:stopWords,
|
61
|
+
:rankingRules,
|
57
62
|
:attributesToHighlight,
|
58
|
-
:attributesToCrop,
|
63
|
+
:attributesToCrop,
|
64
|
+
:cropLength,
|
59
65
|
]
|
60
66
|
|
61
|
-
OPTIONS.each do |
|
62
|
-
define_method
|
63
|
-
instance_variable_set("@#{
|
67
|
+
OPTIONS.each do |option|
|
68
|
+
define_method option do |value|
|
69
|
+
instance_variable_set("@#{option}", value)
|
64
70
|
end
|
71
|
+
|
72
|
+
underscored_name = option.to_s.gsub(/(.)([A-Z])/, '\1_\2').downcase
|
73
|
+
alias_method underscored_name, option if underscored_name != option
|
65
74
|
end
|
66
75
|
|
67
76
|
def initialize(options, &block)
|
@@ -315,7 +324,7 @@ module MeiliSearch
|
|
315
324
|
|
316
325
|
def meilisearch(options = {}, &block)
|
317
326
|
self.meilisearch_settings = IndexSettings.new(options, &block)
|
318
|
-
self.meilisearch_options = { :
|
327
|
+
self.meilisearch_options = { type: ms_full_const_get(model_name.to_s), per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20, page: 1 }.merge(options)
|
319
328
|
|
320
329
|
attr_accessor :formatted
|
321
330
|
|
@@ -552,8 +561,6 @@ module MeiliSearch
|
|
552
561
|
params[:cropLength] = meilisearch_settings.get_setting(:cropLength) if !meilisearch_settings.get_setting(:cropLength).nil?
|
553
562
|
end
|
554
563
|
index = ms_index(index_uid)
|
555
|
-
# index = ms_index(ms_index_uid)
|
556
|
-
# index.search(q, Hash[params.map { |k,v| [k.to_s, v.to_s] }])
|
557
564
|
index.search(q, Hash[params.map { |k,v| [k, v] }])
|
558
565
|
end
|
559
566
|
|
@@ -590,14 +597,6 @@ module MeiliSearch
|
|
590
597
|
params[:limit] = 200
|
591
598
|
end
|
592
599
|
|
593
|
-
if !meilisearch_settings.get_setting(:attributesToHighlight).nil?
|
594
|
-
params[:attributesToHighlight] = meilisearch_settings.get_setting(:attributesToHighlight)
|
595
|
-
end
|
596
|
-
|
597
|
-
if !meilisearch_settings.get_setting(:attributesToCrop).nil?
|
598
|
-
params[:attributesToCrop] = meilisearch_settings.get_setting(:attributesToCrop)
|
599
|
-
params[:cropLength] = meilisearch_settings.get_setting(:cropLength) if !meilisearch_settings.get_setting(:cropLength).nil?
|
600
|
-
end
|
601
600
|
# Returns raw json hits as follows:
|
602
601
|
# {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "nbHits"=>1, "exhaustiveNbHits"=>false, "processingTimeMs"=>0, "query"=>"iphone"}
|
603
602
|
json = ms_raw_search(q, params)
|
@@ -632,7 +631,7 @@ module MeiliSearch
|
|
632
631
|
hits_per_page ||= 20
|
633
632
|
page ||= 1
|
634
633
|
|
635
|
-
res = MeiliSearch::Pagination.create(results, total_hits, meilisearch_options.merge({ :
|
634
|
+
res = MeiliSearch::Pagination.create(results, total_hits, meilisearch_options.merge({ page: page , per_page: hits_per_page }))
|
636
635
|
res.extend(AdditionalMethods)
|
637
636
|
res.send(:ms_init_raw_answer, json)
|
638
637
|
res
|
@@ -823,7 +822,7 @@ module MeiliSearch
|
|
823
822
|
|
824
823
|
def ms_find_in_batches(batch_size, &block)
|
825
824
|
if (defined?(::ActiveRecord) && ancestors.include?(::ActiveRecord::Base)) || respond_to?(:find_in_batches)
|
826
|
-
find_in_batches(:
|
825
|
+
find_in_batches(batch_size: batch_size, &block)
|
827
826
|
elsif defined?(::Sequel) && self < Sequel::Model
|
828
827
|
dataset.extension(:pagination).each_page(batch_size, &block)
|
829
828
|
else
|
@@ -25,12 +25,12 @@ module MeiliSearch
|
|
25
25
|
class << self
|
26
26
|
def create(results, total_hits, options = {})
|
27
27
|
offset = ((options[:page] - 1) * options[:per_page])
|
28
|
-
array = new results, :
|
28
|
+
array = new results, limit: options[:per_page], offset: offset, total_count: total_hits
|
29
29
|
if array.empty? and !results.empty?
|
30
30
|
# since Kaminari 0.16.0, you need to pad the results with nil values so it matches the offset param
|
31
31
|
# otherwise you'll get an empty array: https://github.com/amatsuda/kaminari/commit/29fdcfa8865f2021f710adaedb41b7a7b081e34d
|
32
32
|
results = ([nil] * offset) + results
|
33
|
-
array = new results, :
|
33
|
+
array = new results, offset: offset, limit: options[:per_page], total_count: total_hits
|
34
34
|
end
|
35
35
|
array
|
36
36
|
end
|
data/lib/meilisearch/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/utilities_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
2
|
|
3
|
-
MeiliSearch.configuration = { :
|
3
|
+
MeiliSearch.configuration = { meilisearch_host: ENV['MEILISEARCH_HOST'], meilisearch_api_key: ENV['MEILISEARCH_API_KEY'] }
|
4
4
|
|
5
5
|
describe MeiliSearch::Utilities do
|
6
6
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: meilisearch-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Meili
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|