Skip to content

Commit 9790a66

Browse files
Merge #176
176: Fix primary_key customization r=brunoocasali a=brunoocasali Fixes #147 Co-authored-by: Bruno Casali <[email protected]>
2 parents da629f4 + b02e512 commit 9790a66

File tree

4 files changed

+62
-19
lines changed

4 files changed

+62
-19
lines changed

.rubocop_todo.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2022-07-04 10:10:48 UTC using RuboCop version 1.27.0.
3+
# on 2022-07-22 20:48:41 UTC using RuboCop version 1.27.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
@@ -70,7 +70,7 @@ Metrics/MethodLength:
7070
# Offense count: 1
7171
# Configuration parameters: CountComments, CountAsOne.
7272
Metrics/ModuleLength:
73-
Max: 431
73+
Max: 441
7474

7575
# Offense count: 9
7676
# Configuration parameters: IgnoredMethods.
@@ -108,7 +108,7 @@ RSpec/DescribeClass:
108108
Exclude:
109109
- 'spec/integration_spec.rb'
110110

111-
# Offense count: 27
111+
# Offense count: 29
112112
# Configuration parameters: CountAsOne.
113113
RSpec/ExampleLength:
114114
Max: 19
@@ -185,7 +185,7 @@ Style/RescueModifier:
185185
Exclude:
186186
- 'lib/meilisearch-rails.rb'
187187

188-
# Offense count: 13
188+
# Offense count: 15
189189
# This cop supports safe auto-correction (--auto-correct).
190190
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
191191
# URISchemes: http, https

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,33 @@ end
318318

319319
By default, the primary key is based on your record's id. You can change this behavior by specifying the `primary_key:` option.
320320

321-
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.
322322

323323
```ruby
324324
class Book < ActiveRecord::Base
325325
include MeiliSearch::Rails
326326

327-
meilisearch primary_key: 'ISBN'
327+
meilisearch primary_key: :isbn # isbn is a column in your table definition.
328328
end
329329
```
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.
344+
end
345+
end
346+
```
347+
330348
#### Conditional indexing
331349

332350
You can control if a record must be indexed by using the `if:` or `unless:` options.<br>

lib/meilisearch-rails.rb

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -613,16 +613,30 @@ def ms_search(query, params = {})
613613
# "processingTimeMs"=>0, "query"=>"iphone"}
614614
json = ms_raw_search(query, params)
615615

616-
# Returns the ids of the hits: 13
617-
hit_ids = json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
618-
619616
# condition_key gets the primary key of the document; looks for "id" on the options
620617
condition_key = if defined?(::Mongoid::Document) && include?(::Mongoid::Document)
621618
ms_primary_key_method.in
622619
else
623620
ms_primary_key_method
624621
end
625622

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+
626640
# meilisearch_options[:type] refers to the Model name (e.g. Product)
627641
# results_by_id creates a hash with the primaryKey of the document (id) as the key and doc itself as the value
628642
# {"13"=>#<Product id: 13, name: "iphone", href: "apple", tags: nil, type: nil,

spec/integration_spec.rb

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def will_save_change_to_full_name?
219219
class Cat < ActiveRecord::Base
220220
include MeiliSearch::Rails
221221

222-
meilisearch index_uid: safe_index_uid('animals'), id: :ms_id do
222+
meilisearch index_uid: safe_index_uid('animals'), synchronous: true, primary_key: :ms_id do
223223
end
224224

225225
private
@@ -232,7 +232,7 @@ def ms_id
232232
class Dog < ActiveRecord::Base
233233
include MeiliSearch::Rails
234234

235-
meilisearch index_uid: safe_index_uid('animals'), id: :ms_id do
235+
meilisearch index_uid: safe_index_uid('animals'), synchronous: true, primary_key: :ms_id do
236236
end
237237

238238
private
@@ -359,14 +359,14 @@ class Model < ActiveRecord::Base
359359
class UniqUser < ActiveRecord::Base
360360
include MeiliSearch::Rails
361361

362-
meilisearch synchronous: true, index_uid: safe_index_uid('UniqUser'), id: :name do
362+
meilisearch synchronous: true, index_uid: safe_index_uid('UniqUser'), primary_key: :name do
363363
end
364364
end
365365

366366
class NullableId < ActiveRecord::Base
367367
include MeiliSearch::Rails
368368

369-
meilisearch synchronous: true, index_uid: safe_index_uid('NullableId'), id: :custom_id,
369+
meilisearch synchronous: true, index_uid: safe_index_uid('NullableId'), primary_key: :custom_id,
370370
if: :never do
371371
end
372372

@@ -1370,13 +1370,24 @@ class SerializedDocument < ActiveRecord::Base
13701370
end
13711371

13721372
describe 'Animals' do
1373+
it 'returns only the requested type' do
1374+
Dog.create!([{ name: 'Toby the Dog' }, { name: 'Felix the Dog' }])
1375+
Cat.create!([{ name: 'Toby the Cat' }, { name: 'Felix the Cat' }, { name: 'roar' }])
1376+
1377+
expect(Dog.count).to eq(2)
1378+
expect(Cat.count).to eq(3)
1379+
1380+
expect(Cat.search('felix').size).to eq(1)
1381+
expect(Cat.search('felix').first.name).to eq('Felix the Cat')
1382+
expect(Dog.search('toby').size).to eq(1)
1383+
expect(Dog.search('Toby').first.name).to eq('Toby the Dog')
1384+
end
1385+
13731386
it 'shares a single index' do
1374-
Dog.create!(name: 'Toby')
1375-
Cat.create!(name: 'Felix')
1376-
index = MeiliSearch::Rails.client.index(safe_index_uid('animals'))
1377-
index.wait_for_task(index.tasks['results'].first['uid'])
1378-
docs = index.search('')
1379-
expect(docs['hits'].size).to eq(2)
1387+
cat_index = Cat.index.instance_variable_get('@index').uid
1388+
dog_index = Dog.index.instance_variable_get('@index').uid
1389+
1390+
expect(cat_index).to eq(dog_index)
13801391
end
13811392
end
13821393

0 commit comments

Comments
 (0)