meilisearch-rails 0.5.2 → 0.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2541e903db43e95ae8290c07308159dc9d724949dc1ffa27214df3e52cd37fe6
4
- data.tar.gz: 8b4e32b34e9e3c4fbae0e5c21efa20d87e611ebada16889ba01ba236343b0f6d
3
+ metadata.gz: 2957f44b71394e8f2c6c3e3fa8aa3907b85ef4405c2cbb5230080383eebbe034
4
+ data.tar.gz: 99ebb927e9194b10746355e5ba3ae44853fa4c1ee2e98f6818e910c073f01b8d
5
5
  SHA512:
6
- metadata.gz: 1eba16d0d03695d817998c5249a1ad33d343df4816332a63c7e7b220d42cd2734b9d1ed90e1893a12de6b67d5ed4b1f4e4ca8cad21f3d3e206f8e108f3ffc07f
7
- data.tar.gz: 53ffa781649f9370e7fe35aa5b7263f8792a7f04ede7c28da6e2f6d85b015ae2fcef236affeea659b11c538385a39ca50fb13dab7857d50e8e76067b813f7dfc
6
+ metadata.gz: '08834c370f32354ad47eb1d904212e8535a5b47f89a705ad3aeb42bf7a4768b0dd51f4198b86855f3691c886ccac850f9ef88e6528433a90a9774d6d3bacff0c'
7
+ data.tar.gz: 22ac7b9564df2fef7f23b5227578713d095492f615e9fa652c0d1fb55167d1d9188fda65e4b683db8d413cb38086e27930d1dd6077975b088fd89dfbd1ac8114
data/README.md CHANGED
@@ -30,6 +30,7 @@
30
30
  - [📖 Documentation](#-documentation)
31
31
  - [🤖 Compatibility with Meilisearch](#-compatibility-with-meilisearch)
32
32
  - [🚀 Getting Started](#-getting-started)
33
+ - [Compatibility](#-compatibility)
33
34
  - [⚙️ Settings](#️-settings)
34
35
  - [🔍 Custom search](#-custom-search)
35
36
  - [🪛 Options](#-options)
@@ -43,6 +44,7 @@
43
44
  - [Relations](#relations)
44
45
  - [Sanitize attributes](#sanitize-attributes)
45
46
  - [UTF-8 encoding](#utf-8-encoding)
47
+ - [Eager loading](#eager-loading)
46
48
  - [Manual operations](#manual-operations)
47
49
  - [Indexing & deletion](#indexing--deletion)
48
50
  - [Access the underlying index object](#access-the-underlying-index-object)
@@ -58,7 +60,7 @@ To learn more about Meilisearch, check out our [Documentation](https://docs.meil
58
60
 
59
61
  ## 🤖 Compatibility with Meilisearch
60
62
 
61
- This package only guarantees the compatibility with the [version v0.27.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.27.0).
63
+ This package only guarantees the compatibility with the [version v0.28.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.28.0).
62
64
 
63
65
  ## 🔧 Installation <!-- omit in toc -->
64
66
 
@@ -170,10 +172,10 @@ Then, as soon as you use the `search` method, the returning results will be pagi
170
172
  <%= will_paginate @hits %> # if using will_paginate
171
173
  ```
172
174
 
173
- The **number of hits per page defaults to 20**, you can customize it by adding the `hitsPerPage` parameter to your search:
175
+ The **number of hits per page defaults to 20**, you can customize it by adding the `hits_per_page` parameter to your search:
174
176
 
175
177
  ```ruby
176
- Book.search('harry potter', hitsPerPage: 10)
178
+ Book.search('harry potter', hits_per_page: 10)
177
179
  ```
178
180
 
179
181
  #### Extra Configuration <!-- omit in toc -->
@@ -190,6 +192,10 @@ MeiliSearch::Rails.configuration = {
190
192
  }
191
193
  ```
192
194
 
195
+ ## Compatibility
196
+
197
+ If your model already has methods that meilisearch-rails defines such as `search` and `index`, they will not be redefined. You can target the meilisearch-rails-defined methods by prefixing with `ms_`, e.g. `Book.ms_search('harry potter')`.
198
+
193
199
  ## ⚙️ Settings
194
200
 
195
201
  You can configure the index settings by adding them inside the `meilisearch` block as shown below:
@@ -228,7 +234,7 @@ Check the dedicated section of the documentation, for more information on the [s
228
234
  All the supported options are described in the [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html) section of the documentation.
229
235
 
230
236
  ```ruby
231
- Book.search('Harry', attributesToHighlight: ['*'])
237
+ Book.search('Harry', attributes_to_highlight: ['*'])
232
238
  ```
233
239
  👉 Don't forget that `attributes_to_highlight`, `attributes_to_crop`, and
234
240
  `crop_length` can be set up in the `meilisearch` block of your model.
@@ -256,24 +262,24 @@ By default, the **index_uid** will be the class name, e.g. `Book`. You can custo
256
262
  class Book < ActiveRecord::Base
257
263
  include MeiliSearch::Rails
258
264
 
259
- meilisearch index_uid: 'MyCustomUID' do
260
- end
265
+ meilisearch index_uid: 'MyCustomUID'
261
266
  end
262
267
  ```
263
268
 
264
269
  #### Index UID according to the environment <!-- omit in toc -->
265
270
 
266
- You can suffix the index UID with the current Rails environment using the following option:
271
+ You can suffix the index UID with the current Rails environment by setting it globally:
267
272
 
268
273
  ```ruby
269
- class Book < ActiveRecord::Base
270
- include MeiliSearch::Rails
271
-
272
- meilisearch per_environment: true do # The index UID will be "Book_#{Rails.env}"
273
- end
274
- end
274
+ MeiliSearch::Rails.configuration = {
275
+ meilisearch_host: 'YourMeilisearchHost',
276
+ meilisearch_api_key: 'YourMeilisearchAPIKey',
277
+ per_environment: true
278
+ }
275
279
  ```
276
280
 
281
+ This way your index UID will look like this `"Book_#{Rails.env}"`.
282
+
277
283
  ### Index configuration
278
284
 
279
285
  #### Custom attribute definition
@@ -312,16 +318,33 @@ end
312
318
 
313
319
  By default, the primary key is based on your record's id. You can change this behavior by specifying the `primary_key:` option.
314
320
 
315
- Note that the primary key must have a **unique value**.
321
+ Note that the primary key must return a **unique value** otherwise your data could be overwritten.
316
322
 
317
323
  ```ruby
318
324
  class Book < ActiveRecord::Base
319
325
  include MeiliSearch::Rails
320
326
 
321
- meilisearch primary_key: 'ISBN' do
327
+ meilisearch primary_key: :isbn # isbn is a column in your table definition.
328
+ end
329
+ ```
330
+
331
+ You can also set the `primary_key` as a method, this method will be evaluated in runtime, and its return
332
+ will be used as the reference to the document when Meilisearch needs it.
333
+
334
+ ```rb
335
+ class Book < ActiveRecord::Base
336
+ include MeiliSearch::Rails
337
+
338
+ meilisearch primary_key: :my_custom_ms_id
339
+
340
+ private
341
+
342
+ def my_custom_ms_id
343
+ "isbn_#{primary_key}" # ensure this return is unique, otherwise you'll lose data.
322
344
  end
323
345
  end
324
346
  ```
347
+
325
348
  #### Conditional indexing
326
349
 
327
350
  You can control if a record must be indexed by using the `if:` or `unless:` options.<br>
@@ -331,8 +354,7 @@ As soon as you use those constraints, `add_documents` and `delete_documents` cal
331
354
  class Book < ActiveRecord::Base
332
355
  include MeiliSearch::Rails
333
356
 
334
- meilisearch if: :published?, unless: :premium? do
335
- end
357
+ meilisearch if: :published?, unless: :premium?
336
358
 
337
359
  def published?
338
360
  # [...]
@@ -369,6 +391,7 @@ class Book < ActiveRecord::Base
369
391
  end
370
392
 
371
393
  private
394
+
372
395
  def public?
373
396
  released? && !premium?
374
397
  end
@@ -383,10 +406,10 @@ You may want to share an index between several models. You'll need to ensure you
383
406
  class Cat < ActiveRecord::Base
384
407
  include MeiliSearch::Rails
385
408
 
386
- meilisearch index_uid: 'Animals', primary_key: :ms_id do
387
- end
409
+ meilisearch index_uid: 'Animals', primary_key: :ms_id
388
410
 
389
411
  private
412
+
390
413
  def ms_id
391
414
  "cat_#{primary_key}" # ensure the cats & dogs primary_keys are not conflicting
392
415
  end
@@ -395,10 +418,10 @@ end
395
418
  class Dog < ActiveRecord::Base
396
419
  include MeiliSearch::Rails
397
420
 
398
- meilisearch index_uid: 'Animals', primary_key: :ms_id do
399
- end
421
+ meilisearch index_uid: 'Animals', primary_key: :ms_id
400
422
 
401
423
  private
424
+
402
425
  def ms_id
403
426
  "dog_#{primary_key}" # ensure the cats & dogs primary_keys are not conflicting
404
427
  end
@@ -413,8 +436,7 @@ You can configure the auto-indexing & auto-removal process to use a queue to per
413
436
  class Book < ActiveRecord::Base
414
437
  include MeiliSearch::Rails
415
438
 
416
- meilisearch enqueue: true do # ActiveJob will be triggered using a `meilisearch` queue
417
- end
439
+ meilisearch enqueue: true # ActiveJob will be triggered using a `meilisearch` queue
418
440
  end
419
441
  ```
420
442
 
@@ -586,8 +608,7 @@ You can strip all HTML tags from your attributes with the `sanitize` option.
586
608
  class Book < ActiveRecord::Base
587
609
  include MeiliSearch::Rails
588
610
 
589
- meilisearch sanitize: true do
590
- end
611
+ meilisearch sanitize: true
591
612
  end
592
613
  ```
593
614
 
@@ -599,8 +620,21 @@ You can force the UTF-8 encoding of all your attributes using the `force_utf8_en
599
620
  class Book < ActiveRecord::Base
600
621
  include MeiliSearch::Rails
601
622
 
602
- meilisearch force_utf8_encoding: true do
603
- end
623
+ meilisearch force_utf8_encoding: true
624
+ end
625
+ ```
626
+
627
+ #### Eager loading
628
+
629
+ You can eager load associations using `meilisearch_import` scope.
630
+
631
+ ```ruby
632
+ class Author < ActiveRecord::Base
633
+ include MeiliSearch::Rails
634
+
635
+ has_many :books
636
+
637
+ scope :meilisearch_import, -> { includes(:books) }
604
638
  end
605
639
  ```
606
640
 
@@ -652,8 +686,7 @@ class Book < ActiveRecord::Base
652
686
  include MeiliSearch::Rails
653
687
 
654
688
  # Only raise exceptions in development environment.
655
- meilisearch raise_on_failure: Rails.env.development? do
656
- end
689
+ meilisearch raise_on_failure: Rails.env.development?
657
690
  end
658
691
  ```
659
692
 
@@ -667,8 +700,7 @@ You can force indexing and removing to be synchronous by setting the following o
667
700
  class Book < ActiveRecord::Base
668
701
  include MeiliSearch::Rails
669
702
 
670
- meilisearch synchronous: true do
671
- end
703
+ meilisearch synchronous: true
672
704
  end
673
705
  ```
674
706
  🚨 This is only recommended for testing purposes, the gem will call the `wait_for_task` method that will stop your code execution until the asynchronous task has been processed by MeilSearch.
@@ -681,8 +713,7 @@ You can disable auto-indexing and auto-removing setting the following options:
681
713
  class Book < ActiveRecord::Base
682
714
  include MeiliSearch::Rails
683
715
 
684
- meilisearch auto_index: false, auto_remove: false do
685
- end
716
+ meilisearch auto_index: false, auto_remove: false
686
717
  end
687
718
  ```
688
719
 
@@ -16,6 +16,7 @@ module MeiliSearch
16
16
  configuration[:meilisearch_host] || 'http://localhost:7700',
17
17
  configuration[:meilisearch_api_key],
18
18
  configuration.slice(:timeout, :max_retries)
19
+ .merge(client_agents: MeiliSearch::Rails.qualified_version)
19
20
  )
20
21
  end
21
22
  end
@@ -2,6 +2,10 @@
2
2
 
3
3
  module MeiliSearch
4
4
  module Rails
5
- VERSION = '0.5.2'
5
+ VERSION = '0.7.1'
6
+
7
+ def self.qualified_version
8
+ "Meilisearch Rails (v#{VERSION})"
9
+ end
6
10
  end
7
11
  end
@@ -105,7 +105,7 @@ module MeiliSearch
105
105
  end
106
106
 
107
107
  def sequel?(document)
108
- defined?(::Sequel) && document.class < ::Sequel::Model
108
+ defined?(::Sequel::Model) && document.class < ::Sequel::Model
109
109
  end
110
110
 
111
111
  def active_record?(document)
@@ -233,9 +233,13 @@ module MeiliSearch
233
233
  def initialize(index_uid, raise_on_failure, options)
234
234
  client = MeiliSearch::Rails.client
235
235
  primary_key = options[:primary_key] || MeiliSearch::Rails::IndexSettings::DEFAULT_PRIMARY_KEY
236
- client.create_index(index_uid, { primaryKey: primary_key })
237
- @index = client.index(index_uid)
238
236
  @raise_on_failure = raise_on_failure.nil? || raise_on_failure
237
+
238
+ SafeIndex.log_or_throw(nil, @raise_on_failure) do
239
+ client.create_index(index_uid, { primary_key: primary_key })
240
+ end
241
+
242
+ @index = client.index(index_uid)
239
243
  end
240
244
 
241
245
  ::MeiliSearch::Index.instance_methods(false).each do |m|
@@ -273,7 +277,7 @@ module MeiliSearch
273
277
 
274
278
  def self.log_or_throw(method, raise_on_failure, &block)
275
279
  yield
276
- rescue ::MeiliSearch::ApiError => e
280
+ rescue ::MeiliSearch::TimeoutError, ::MeiliSearch::ApiError => e
277
281
  raise e if raise_on_failure
278
282
 
279
283
  # log the error
@@ -282,7 +286,7 @@ module MeiliSearch
282
286
  case method.to_s
283
287
  when 'search'
284
288
  # some attributes are required
285
- { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetsDistribution' => {}, 'error' => e }
289
+ { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetDistribution' => {}, 'error' => e }
286
290
  else
287
291
  # empty answer
288
292
  { 'error' => e }
@@ -319,8 +323,12 @@ module MeiliSearch
319
323
 
320
324
  attr_accessor :formatted
321
325
 
326
+ if options.key?(:per_environment)
327
+ raise BadConfiguration, ':per_environment option should be defined globally on MeiliSearch::Rails.configuration block.'
328
+ end
329
+
322
330
  if options[:synchronous] == true
323
- if defined?(::Sequel) && self < Sequel::Model
331
+ if defined?(::Sequel::Model) && self < Sequel::Model
324
332
  class_eval do
325
333
  copy_after_validation = instance_method(:after_validation)
326
334
  define_method(:after_validation) do |*args|
@@ -352,7 +360,7 @@ module MeiliSearch
352
360
  end
353
361
  end
354
362
  unless options[:auto_index] == false
355
- if defined?(::Sequel) && self < Sequel::Model
363
+ if defined?(::Sequel::Model) && self < Sequel::Model
356
364
  class_eval do
357
365
  copy_after_validation = instance_method(:after_validation)
358
366
  copy_before_save = instance_method(:before_save)
@@ -399,7 +407,7 @@ module MeiliSearch
399
407
  end
400
408
  end
401
409
  unless options[:auto_remove] == false
402
- if defined?(::Sequel) && self < Sequel::Model
410
+ if defined?(::Sequel::Model) && self < Sequel::Model
403
411
  class_eval do
404
412
  copy_after_destroy = instance_method(:after_destroy)
405
413
 
@@ -456,7 +464,7 @@ module MeiliSearch
456
464
  end
457
465
  last_task = index.add_documents(documents)
458
466
  end
459
- index.wait_for_task(last_task['uid']) if last_task && (synchronous || options[:synchronous])
467
+ index.wait_for_task(last_task['taskUid']) if last_task && (synchronous || options[:synchronous])
460
468
  end
461
469
  nil
462
470
  end
@@ -472,7 +480,7 @@ module MeiliSearch
472
480
 
473
481
  index = SafeIndex.new(ms_index_uid(options), true, options)
474
482
  task = index.update_settings(final_settings)
475
- index.wait_for_task(task['uid']) if synchronous
483
+ index.wait_for_task(task['taskUid']) if synchronous
476
484
  end
477
485
  end
478
486
 
@@ -482,7 +490,7 @@ module MeiliSearch
482
490
 
483
491
  index = ms_ensure_init(options, settings)
484
492
  task = index.add_documents(documents.map { |d| settings.get_attributes(d).merge ms_pk(options) => ms_primary_key_of(d, options) })
485
- index.wait_for_task(task['uid']) if synchronous || options[:synchronous]
493
+ index.wait_for_task(task['taskUid']) if synchronous || options[:synchronous]
486
494
  end
487
495
  end
488
496
 
@@ -579,7 +587,7 @@ module MeiliSearch
579
587
  end
580
588
 
581
589
  def ms_facets_distribution
582
- @ms_json['facetsDistribution']
590
+ @ms_json['facetDistribution']
583
591
  end
584
592
 
585
593
  private
@@ -601,13 +609,10 @@ module MeiliSearch
601
609
  end
602
610
 
603
611
  # Returns raw json hits as follows:
604
- # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "nbHits"=>1,
605
- # "exhaustiveNbHits"=>false, "processingTimeMs"=>0, "query"=>"iphone"}
612
+ # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "estimatedTotalHits"=>1,
613
+ # "processingTimeMs"=>0, "query"=>"iphone"}
606
614
  json = ms_raw_search(query, params)
607
615
 
608
- # Returns the ids of the hits: 13
609
- hit_ids = json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
610
-
611
616
  # condition_key gets the primary key of the document; looks for "id" on the options
612
617
  condition_key = if defined?(::Mongoid::Document) && include?(::Mongoid::Document)
613
618
  ms_primary_key_method.in
@@ -615,6 +620,23 @@ module MeiliSearch
615
620
  ms_primary_key_method
616
621
  end
617
622
 
623
+ # The condition_key must be a valid column otherwise, the `.where` below will not work
624
+ # Since we provide a way to customize the primary_key value, `ms_pk(meilisearch_options)` may not
625
+ # respond with a valid database column. The blocks below prevent that from happening.
626
+ has_virtual_column_as_pk = if defined?(::Sequel::Model) && self < Sequel::Model
627
+ meilisearch_options[:type].columns.map(&:to_s).exclude?(condition_key.to_s)
628
+ else
629
+ meilisearch_options[:type].columns.map(&:name).map(&:to_s).exclude?(condition_key.to_s)
630
+ end
631
+
632
+ condition_key = meilisearch_options[:type].primary_key if has_virtual_column_as_pk
633
+
634
+ hit_ids = if has_virtual_column_as_pk
635
+ json['hits'].map { |hit| hit[condition_key] }
636
+ else
637
+ json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
638
+ end
639
+
618
640
  # meilisearch_options[:type] refers to the Model name (e.g. Product)
619
641
  # results_by_id creates a hash with the primaryKey of the document (id) as the key and doc itself as the value
620
642
  # {"13"=>#<Product id: 13, name: "iphone", href: "apple", tags: nil, type: nil,
@@ -653,8 +675,11 @@ module MeiliSearch
653
675
 
654
676
  def ms_index_uid(options = nil)
655
677
  options ||= meilisearch_options
678
+ global_options ||= MeiliSearch::Rails.configuration
679
+
656
680
  name = options[:index_uid] || model_name.to_s.gsub('::', '_')
657
- name = "#{name}_#{::Rails.env}" if options[:per_environment]
681
+ name = "#{name}_#{::Rails.env}" if global_options[:per_environment]
682
+
658
683
  name
659
684
  end
660
685
 
@@ -820,8 +845,9 @@ module MeiliSearch
820
845
 
821
846
  def ms_find_in_batches(batch_size, &block)
822
847
  if (defined?(::ActiveRecord) && ancestors.include?(::ActiveRecord::Base)) || respond_to?(:find_in_batches)
823
- find_in_batches(batch_size: batch_size, &block)
824
- elsif defined?(::Sequel) && self < Sequel::Model
848
+ scope = respond_to?(:meilisearch_import) ? meilisearch_import : all
849
+ scope.find_in_batches(batch_size: batch_size, &block)
850
+ elsif defined?(::Sequel::Model) && self < Sequel::Model
825
851
  dataset.extension(:pagination).each_page(batch_size, &block)
826
852
  else
827
853
  # don't worry, mongoid has its own underlying cursor/streaming mechanism
@@ -903,7 +929,7 @@ module MeiliSearch
903
929
  # ms_must_reindex flag is reset after every commit as part. If we must reindex at any point in
904
930
  # a transaction, keep flag set until it is explicitly unset
905
931
  @ms_must_reindex ||=
906
- if defined?(::Sequel) && is_a?(Sequel::Model)
932
+ if defined?(::Sequel::Model) && is_a?(Sequel::Model)
907
933
  new? || self.class.ms_must_reindex?(self)
908
934
  else
909
935
  new_record? || self.class.ms_must_reindex?(self)
@@ -34,5 +34,5 @@ Gem::Specification.new do |s|
34
34
 
35
35
  s.required_ruby_version = '>= 2.6.0'
36
36
 
37
- s.add_dependency 'meilisearch', '~> 0.18'
37
+ s.add_dependency 'meilisearch', '~> 0.19.2'
38
38
  end
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.5.2
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Meili
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-18 00:00:00.000000000 Z
11
+ date: 2022-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: meilisearch
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.18'
19
+ version: 0.19.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.18'
26
+ version: 0.19.2
27
27
  description: Meilisearch integration for Ruby on Rails. See https://github.com/meilisearch/meilisearch
28
28
  email: bonjour@meilisearch.com
29
29
  executables: []