pg_search 2.1.4 → 2.1.5
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/.rubocop.yml +2 -4
- data/.travis.yml +27 -25
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -4
- data/README.md +184 -151
- data/Rakefile +1 -5
- data/lib/pg_search.rb +1 -1
- data/lib/pg_search/configuration.rb +2 -2
- data/lib/pg_search/document.rb +3 -3
- data/lib/pg_search/features/dmetaphone.rb +1 -1
- data/lib/pg_search/features/feature.rb +1 -1
- data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +1 -1
- data/lib/pg_search/multisearch.rb +1 -1
- data/lib/pg_search/multisearchable.rb +4 -4
- data/lib/pg_search/scope_options.rb +13 -28
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +1 -2
- data/spec/integration/associations_spec.rb +100 -100
- data/spec/integration/pagination_spec.rb +7 -7
- data/spec/integration/pg_search_spec.rb +225 -225
- data/spec/integration/single_table_inheritance_spec.rb +14 -14
- data/spec/lib/pg_search/configuration/association_spec.rb +5 -5
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +1 -1
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +2 -2
- data/spec/lib/pg_search/features/trigram_spec.rb +1 -1
- data/spec/lib/pg_search/features/tsearch_spec.rb +12 -12
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +10 -10
- data/spec/lib/pg_search/multisearch_spec.rb +5 -5
- data/spec/lib/pg_search/multisearchable_spec.rb +26 -26
- data/spec/lib/pg_search/normalizer_spec.rb +5 -5
- data/spec/lib/pg_search_spec.rb +30 -30
- data/spec/spec_helper.rb +1 -1
- data/spec/support/database.rb +12 -19
- metadata +4 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37f3b1c59cc5c10933bcec4bdb40902714172e666537bb7ac43f8c43a4acd43c
|
4
|
+
data.tar.gz: 30132ced7cbe402c69ccdc0affeb3224ab31690d2cf6ca260b00d21d7602d42c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9157dc3eeb50d6bcdf20745c89888ff855a01679de95135c84f58f6b5efe88df0a5d9e813d18acc16376041e63eed118785847667da46e429abf46ef955fcde3
|
7
|
+
data.tar.gz: c548d7841d812553ed0dbbf6ab50decd833a0b271fe799be9989c7ff03c320451f8658930c8abaca87da70d812dc18c904a900ff91b44b96305eb7fdf55a70f8
|
data/.rubocop.yml
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
2
|
+
TargetRubyVersion: 2.4
|
3
3
|
Exclude:
|
4
4
|
- bin/**/*
|
5
|
+
- vendor/**/*
|
5
6
|
|
6
7
|
Style/StringLiterals:
|
7
8
|
Enabled: false
|
@@ -19,9 +20,6 @@ Metrics/BlockLength:
|
|
19
20
|
Layout/AlignParameters:
|
20
21
|
EnforcedStyle: with_fixed_indentation
|
21
22
|
|
22
|
-
Style/HashSyntax:
|
23
|
-
Enabled: false
|
24
|
-
|
25
23
|
Style/NumericPredicate:
|
26
24
|
Enabled: false
|
27
25
|
|
data/.travis.yml
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
language: ruby
|
2
2
|
sudo: false
|
3
3
|
bundler_args: --binstubs
|
4
|
-
|
4
|
+
cache: bundler
|
5
5
|
|
6
6
|
rvm:
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
10
|
-
-
|
11
|
-
- "jruby-9.2.5.0"
|
7
|
+
- 2.6.2
|
8
|
+
- 2.5.5
|
9
|
+
- 2.4.5
|
10
|
+
- jruby-9.2.6.0
|
12
11
|
|
13
12
|
env:
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
global:
|
14
|
+
- CC_TEST_REPORTER_ID=0a0e3e45118bc447e677d52c21d056a5471c4921d54f96ed7b2550d9fc5043ea
|
15
|
+
matrix:
|
16
|
+
- ACTIVE_RECORD_BRANCH="master"
|
17
|
+
- ACTIVE_RECORD_BRANCH="5-2-stable"
|
18
|
+
- ACTIVE_RECORD_VERSION="~> 6.0.0.beta1"
|
19
|
+
- ACTIVE_RECORD_VERSION="~> 5.2.0"
|
20
|
+
- ACTIVE_RECORD_VERSION="~> 5.1.0"
|
21
|
+
- ACTIVE_RECORD_VERSION="~> 5.0.0"
|
22
|
+
- ACTIVE_RECORD_VERSION="~> 4.2.9"
|
21
23
|
|
22
24
|
matrix:
|
23
25
|
allow_failures:
|
@@ -25,24 +27,24 @@ matrix:
|
|
25
27
|
- env: ACTIVE_RECORD_BRANCH="5-2-stable"
|
26
28
|
- env: ACTIVE_RECORD_VERSION="~> 6.0.0.beta1"
|
27
29
|
exclude:
|
28
|
-
- rvm:
|
30
|
+
- rvm: 2.4.5
|
29
31
|
env: ACTIVE_RECORD_BRANCH="master"
|
30
|
-
- rvm:
|
31
|
-
env: ACTIVE_RECORD_BRANCH="master"
|
32
|
-
- rvm: jruby-9.2.5.0
|
32
|
+
- rvm: jruby-9.2.6.0
|
33
33
|
env: ACTIVE_RECORD_VERSION="~> 4.2.9"
|
34
|
-
- rvm:
|
35
|
-
env: ACTIVE_RECORD_VERSION="~> 6.0.0.beta1"
|
36
|
-
- rvm: "2.4.5"
|
34
|
+
- rvm: 2.4.5
|
37
35
|
env: ACTIVE_RECORD_VERSION="~> 6.0.0.beta1"
|
38
36
|
|
39
37
|
before_script:
|
40
|
-
-
|
41
|
-
-
|
38
|
+
- psql --version
|
39
|
+
- psql -c 'create database pg_search_test;' -U postgres >/dev/null
|
40
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
41
|
+
- chmod +x ./cc-test-reporter
|
42
|
+
- ./cc-test-reporter before-build
|
43
|
+
|
44
|
+
script: bin/rake
|
42
45
|
|
43
|
-
|
46
|
+
after_script:
|
47
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
44
48
|
|
45
49
|
addons:
|
46
50
|
postgresql: "9.6"
|
47
|
-
code_climate:
|
48
|
-
repo_token: 0a0e3e45118bc447e677d52c21d056a5471c4921d54f96ed7b2550d9fc5043ea
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -4,12 +4,12 @@ source 'https://rubygems.org'
|
|
4
4
|
|
5
5
|
gemspec
|
6
6
|
|
7
|
-
gem 'pg', '>= 0.21.0', '< 1.0.0', :
|
8
|
-
gem "activerecord-jdbcpostgresql-adapter", ">= 1.3.1", :
|
7
|
+
gem 'pg', '>= 0.21.0', '< 1.0.0', platform: :ruby
|
8
|
+
gem "activerecord-jdbcpostgresql-adapter", ">= 1.3.1", platform: :jruby
|
9
9
|
|
10
10
|
if ENV['ACTIVE_RECORD_BRANCH']
|
11
|
-
gem 'activerecord', :
|
12
|
-
gem 'arel', :
|
11
|
+
gem 'activerecord', git: 'https://github.com/rails/rails.git', branch: ENV['ACTIVE_RECORD_BRANCH']
|
12
|
+
gem 'arel', git: 'https://github.com/rails/arel.git' if ENV['ACTIVE_RECORD_BRANCH'] == 'master'
|
13
13
|
end
|
14
14
|
|
15
15
|
gem 'activerecord', ENV['ACTIVE_RECORD_VERSION'] if ENV['ACTIVE_RECORD_VERSION']
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ Read the blog post introducing PgSearch at https://content.pivotal.io/blog/pg-se
|
|
17
17
|
|
18
18
|
## REQUIREMENTS
|
19
19
|
|
20
|
-
* Ruby 2.
|
20
|
+
* Ruby 2.4+
|
21
21
|
* ActiveRecord 4.2+
|
22
22
|
* PostgreSQL 9.2+
|
23
23
|
* [PostgreSQL extensions](https://github.com/Casecommons/pg_search/wiki/Installing-PostgreSQL-Extensions) for certain features
|
@@ -89,12 +89,12 @@ multisearchable in its class definition.
|
|
89
89
|
```ruby
|
90
90
|
class EpicPoem < ActiveRecord::Base
|
91
91
|
include PgSearch
|
92
|
-
multisearchable :
|
92
|
+
multisearchable against: [:title, :author]
|
93
93
|
end
|
94
94
|
|
95
95
|
class Flower < ActiveRecord::Base
|
96
96
|
include PgSearch
|
97
|
-
multisearchable :
|
97
|
+
multisearchable against: :color
|
98
98
|
end
|
99
99
|
```
|
100
100
|
|
@@ -114,14 +114,14 @@ particular record should be included.
|
|
114
114
|
```ruby
|
115
115
|
class Convertible < ActiveRecord::Base
|
116
116
|
include PgSearch
|
117
|
-
multisearchable :
|
118
|
-
:
|
117
|
+
multisearchable against: [:make, :model],
|
118
|
+
if: :available_in_red?
|
119
119
|
end
|
120
120
|
|
121
121
|
class Jalopy < ActiveRecord::Base
|
122
122
|
include PgSearch
|
123
|
-
multisearchable :
|
124
|
-
:
|
123
|
+
multisearchable against: [:make, :model],
|
124
|
+
if: lambda { |record| record.model_year > 1970 }
|
125
125
|
end
|
126
126
|
```
|
127
127
|
|
@@ -134,8 +134,8 @@ timestamp.
|
|
134
134
|
```ruby
|
135
135
|
class AntipatternExample
|
136
136
|
include PgSearch
|
137
|
-
multisearchable :
|
138
|
-
:
|
137
|
+
multisearchable against: [:contents],
|
138
|
+
if: :published?
|
139
139
|
|
140
140
|
def published?
|
141
141
|
published_at < Time.now
|
@@ -143,8 +143,8 @@ class AntipatternExample
|
|
143
143
|
end
|
144
144
|
|
145
145
|
problematic_record = AntipatternExample.create!(
|
146
|
-
:
|
147
|
-
:
|
146
|
+
contents: "Using :if with a timestamp",
|
147
|
+
published_at: 10.minutes.from_now
|
148
148
|
)
|
149
149
|
|
150
150
|
problematic_record.published? # => false
|
@@ -161,6 +161,46 @@ problematic_record.published? # => true
|
|
161
161
|
PgSearch.multisearch("timestamp") # => Includes problematic_record
|
162
162
|
```
|
163
163
|
|
164
|
+
#### More Options
|
165
|
+
|
166
|
+
**Conditionally update pg_search_documents**
|
167
|
+
|
168
|
+
You can specify an `:update_if` parameter to conditionally update pg_search documents. For example:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
multisearchable(
|
172
|
+
against: [:body],
|
173
|
+
update_if: :body_changed?
|
174
|
+
)
|
175
|
+
```
|
176
|
+
|
177
|
+
**Specify additional attributes to be saved on the pg_search_documents table**
|
178
|
+
|
179
|
+
You can specify `:additional_attributes` to be saved within the pg_search_documents table. For example, perhaps you are indexing a book model and an article model and wanted to include the author_id.
|
180
|
+
|
181
|
+
First, we need to add `author_id` to the migration creating our pg_search_documents table.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
create_table :pg_search_documents do |t|
|
185
|
+
t.text :content
|
186
|
+
t.integer :author_id
|
187
|
+
t.belongs_to :searchable, polymorphic: true, index: true
|
188
|
+
```
|
189
|
+
|
190
|
+
Then, we can send in this additional attribute in a lambda
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
multisearchable(
|
194
|
+
against: [:title, :body],
|
195
|
+
additional_attributes: -> (article) { { author_id: article.author_id } }
|
196
|
+
)
|
197
|
+
```
|
198
|
+
|
199
|
+
This allows much faster searches without joins later on by doing something like:
|
200
|
+
`PgSearch.multisearch(params['search']).where(author_id: 2)`
|
201
|
+
|
202
|
+
*NOTE: You must currently manually call `record.update_pg_search_document` for the additional attribute to be included in the pg_search_documents table*
|
203
|
+
|
164
204
|
#### Multi-search associations
|
165
205
|
|
166
206
|
Two associations are built automatically. On the original record, there is a
|
@@ -169,7 +209,7 @@ record, and on the PgSearch::Document record there is a belongs_to :searchable
|
|
169
209
|
polymorphic association pointing back to the original record.
|
170
210
|
|
171
211
|
```ruby
|
172
|
-
odyssey = EpicPoem.create!(:
|
212
|
+
odyssey = EpicPoem.create!(title: "Odyssey", author: "Homer")
|
173
213
|
search_document = odyssey.pg_search_document #=> PgSearch::Document instance
|
174
214
|
search_document.searchable #=> #<EpicPoem id: 1, title: "Odyssey", author: "Homer">
|
175
215
|
```
|
@@ -180,8 +220,8 @@ To fetch the PgSearch::Document entries for all of the records that match a
|
|
180
220
|
given query, use PgSearch.multisearch.
|
181
221
|
|
182
222
|
```ruby
|
183
|
-
odyssey = EpicPoem.create!(:
|
184
|
-
rose = Flower.create!(:
|
223
|
+
odyssey = EpicPoem.create!(title: "Odyssey", author: "Homer")
|
224
|
+
rose = Flower.create!(color: "Red")
|
185
225
|
PgSearch.multisearch("Homer") #=> [#<PgSearch::Document searchable: odyssey>]
|
186
226
|
PgSearch.multisearch("Red") #=> [#<PgSearch::Document searchable: rose>]
|
187
227
|
```
|
@@ -195,7 +235,7 @@ receive SQL requests when necessary.
|
|
195
235
|
|
196
236
|
```ruby
|
197
237
|
PgSearch.multisearch("Bertha").limit(10)
|
198
|
-
PgSearch.multisearch("Juggler").where(:
|
238
|
+
PgSearch.multisearch("Juggler").where(searchable_type: "Occupation")
|
199
239
|
PgSearch.multisearch("Alamo").page(3).per(30)
|
200
240
|
PgSearch.multisearch("Diagonal").find_each do |document|
|
201
241
|
puts document.searchable.updated_at
|
@@ -212,8 +252,8 @@ PgSearch.multisearch_options in an initializer:
|
|
212
252
|
|
213
253
|
```ruby
|
214
254
|
PgSearch.multisearch_options = {
|
215
|
-
:
|
216
|
-
:
|
255
|
+
using: [:tsearch, :trigram],
|
256
|
+
ignoring: :accents
|
217
257
|
}
|
218
258
|
```
|
219
259
|
|
@@ -234,7 +274,7 @@ To remove all of the documents for a given class, you can simply delete all of
|
|
234
274
|
the PgSearch::Document records.
|
235
275
|
|
236
276
|
```ruby
|
237
|
-
PgSearch::Document.delete_all(:
|
277
|
+
PgSearch::Document.delete_all(searchable_type: "Animal")
|
238
278
|
```
|
239
279
|
|
240
280
|
To regenerate the documents for a given class, run:
|
@@ -270,7 +310,7 @@ the pg_search_documents table all at once. However, if you call any dynamic
|
|
270
310
|
methods in :against, the following strategy will be used:
|
271
311
|
|
272
312
|
```ruby
|
273
|
-
PgSearch::Document.delete_all(:
|
313
|
+
PgSearch::Document.delete_all(searchable_type: "Ingredient")
|
274
314
|
Ingredient.find_each { |record| record.update_pg_search_document }
|
275
315
|
```
|
276
316
|
|
@@ -336,7 +376,7 @@ To search against a column, pass a symbol as the :against option.
|
|
336
376
|
```ruby
|
337
377
|
class BlogPost < ActiveRecord::Base
|
338
378
|
include PgSearch
|
339
|
-
pg_search_scope :search_by_title, :
|
379
|
+
pg_search_scope :search_by_title, against: :title
|
340
380
|
end
|
341
381
|
```
|
342
382
|
|
@@ -344,8 +384,8 @@ We now have an ActiveRecord scope named search_by_title on our BlogPost model.
|
|
344
384
|
It takes one parameter, a search query string.
|
345
385
|
|
346
386
|
```ruby
|
347
|
-
BlogPost.create!(:
|
348
|
-
BlogPost.create!(:
|
387
|
+
BlogPost.create!(title: "Recent Developments in the World of Pastrami")
|
388
|
+
BlogPost.create!(title: "Prosciutto and You: A Retrospective")
|
349
389
|
BlogPost.search_by_title("pastrami") # => [#<BlogPost id: 2, title: "Recent Developments in the World of Pastrami">]
|
350
390
|
```
|
351
391
|
|
@@ -356,15 +396,15 @@ Just pass an Array if you'd like to search more than one column.
|
|
356
396
|
```ruby
|
357
397
|
class Person < ActiveRecord::Base
|
358
398
|
include PgSearch
|
359
|
-
pg_search_scope :search_by_full_name, :
|
399
|
+
pg_search_scope :search_by_full_name, against: [:first_name, :last_name]
|
360
400
|
end
|
361
401
|
```
|
362
402
|
|
363
403
|
Now our search query can match either or both of the columns.
|
364
404
|
|
365
405
|
```ruby
|
366
|
-
person_1 = Person.create!(:
|
367
|
-
person_2 = Person.create!(:
|
406
|
+
person_1 = Person.create!(first_name: "Grant", last_name: "Hill")
|
407
|
+
person_2 = Person.create!(first_name: "Hugh", last_name: "Grant")
|
368
408
|
|
369
409
|
Person.search_by_full_name("Grant") # => [person_1, person_2]
|
370
410
|
Person.search_by_full_name("Grant Hill") # => [person_1]
|
@@ -386,14 +426,14 @@ class Person < ActiveRecord::Base
|
|
386
426
|
pg_search_scope :search_by_name, lambda { |name_part, query|
|
387
427
|
raise ArgumentError unless [:first, :last].include?(name_part)
|
388
428
|
{
|
389
|
-
:
|
390
|
-
:
|
429
|
+
against: name_part,
|
430
|
+
query: query
|
391
431
|
}
|
392
432
|
}
|
393
433
|
end
|
394
434
|
|
395
|
-
person_1 = Person.create!(:
|
396
|
-
person_2 = Person.create!(:
|
435
|
+
person_1 = Person.create!(first_name: "Grant", last_name: "Hill")
|
436
|
+
person_2 = Person.create!(first_name: "Hugh", last_name: "Grant")
|
397
437
|
|
398
438
|
Person.search_by_name :first, "Grant" # => [person_1]
|
399
439
|
Person.search_by_name :last, "Grant" # => [person_2]
|
@@ -423,11 +463,11 @@ class Salami < ActiveRecord::Base
|
|
423
463
|
include PgSearch
|
424
464
|
|
425
465
|
belongs_to :cracker
|
426
|
-
has_many :cheeses, :
|
466
|
+
has_many :cheeses, through: :cracker
|
427
467
|
|
428
|
-
pg_search_scope :tasty_search, :
|
429
|
-
:
|
430
|
-
:
|
468
|
+
pg_search_scope :tasty_search, associated_against: {
|
469
|
+
cheeses: [:kind, :brand],
|
470
|
+
cracker: :kind
|
431
471
|
}
|
432
472
|
end
|
433
473
|
|
@@ -435,13 +475,13 @@ salami_1 = Salami.create!
|
|
435
475
|
salami_2 = Salami.create!
|
436
476
|
salami_3 = Salami.create!
|
437
477
|
|
438
|
-
limburger = Cheese.create!(:
|
439
|
-
brie = Cheese.create!(:
|
440
|
-
pepper_jack = Cheese.create!(:
|
478
|
+
limburger = Cheese.create!(kind: "Limburger")
|
479
|
+
brie = Cheese.create!(kind: "Brie")
|
480
|
+
pepper_jack = Cheese.create!(kind: "Pepper Jack")
|
441
481
|
|
442
|
-
Cracker.create!(:
|
443
|
-
Cracker.create!(:
|
444
|
-
Cracker.create!(:
|
482
|
+
Cracker.create!(kind: "Black Pepper", cheeses: [brie], salami: salami_1)
|
483
|
+
Cracker.create!(kind: "Ritz", cheeses: [limburger, pepper_jack], salami: salami_2)
|
484
|
+
Cracker.create!(kind: "Graham", cheeses: [limburger], salami: salami_3)
|
445
485
|
|
446
486
|
Salami.tasty_search("pepper") # => [salami_1, salami_2]
|
447
487
|
```
|
@@ -456,7 +496,7 @@ search techniques.
|
|
456
496
|
```ruby
|
457
497
|
class Beer < ActiveRecord::Base
|
458
498
|
include PgSearch
|
459
|
-
pg_search_scope :search_name, :
|
499
|
+
pg_search_scope :search_name, against: :name, using: [:tsearch, :trigram, :dmetaphone]
|
460
500
|
end
|
461
501
|
```
|
462
502
|
|
@@ -482,10 +522,10 @@ subtitle, and finally the content.
|
|
482
522
|
```ruby
|
483
523
|
class NewsArticle < ActiveRecord::Base
|
484
524
|
include PgSearch
|
485
|
-
pg_search_scope :search_full_text, :
|
486
|
-
:
|
487
|
-
:
|
488
|
-
:
|
525
|
+
pg_search_scope :search_full_text, against: {
|
526
|
+
title: 'A',
|
527
|
+
subtitle: 'B',
|
528
|
+
content: 'C'
|
489
529
|
}
|
490
530
|
end
|
491
531
|
```
|
@@ -497,7 +537,7 @@ weight. If you omit the weight, a default will be used.
|
|
497
537
|
```ruby
|
498
538
|
class NewsArticle < ActiveRecord::Base
|
499
539
|
include PgSearch
|
500
|
-
pg_search_scope :search_full_text, :
|
540
|
+
pg_search_scope :search_full_text, against: [
|
501
541
|
[:title, 'A'],
|
502
542
|
[:subtitle, 'B'],
|
503
543
|
[:content, 'C']
|
@@ -506,9 +546,9 @@ end
|
|
506
546
|
|
507
547
|
class NewsArticle < ActiveRecord::Base
|
508
548
|
include PgSearch
|
509
|
-
pg_search_scope :search_full_text, :
|
549
|
+
pg_search_scope :search_full_text, against: [
|
510
550
|
[:title, 'A'],
|
511
|
-
{:
|
551
|
+
{subtitle: 'B'},
|
512
552
|
:content
|
513
553
|
]
|
514
554
|
end
|
@@ -525,15 +565,15 @@ shown in the following example.
|
|
525
565
|
class Superhero < ActiveRecord::Base
|
526
566
|
include PgSearch
|
527
567
|
pg_search_scope :whose_name_starts_with,
|
528
|
-
:
|
529
|
-
:
|
530
|
-
:
|
568
|
+
against: :name,
|
569
|
+
using: {
|
570
|
+
tsearch: { prefix: true }
|
531
571
|
}
|
532
572
|
end
|
533
573
|
|
534
|
-
batman = Superhero.create :
|
535
|
-
batgirl = Superhero.create :
|
536
|
-
robin = Superhero.create :
|
574
|
+
batman = Superhero.create name: 'Batman'
|
575
|
+
batgirl = Superhero.create name: 'Batgirl'
|
576
|
+
robin = Superhero.create name: 'Robin'
|
537
577
|
|
538
578
|
Superhero.whose_name_starts_with("Bat") # => [batman, batgirl]
|
539
579
|
```
|
@@ -554,16 +594,16 @@ term that you were trying to exclude.
|
|
554
594
|
class Animal < ActiveRecord::Base
|
555
595
|
include PgSearch
|
556
596
|
pg_search_scope :with_name_matching,
|
557
|
-
:
|
558
|
-
:
|
559
|
-
:
|
597
|
+
against: :name,
|
598
|
+
using: {
|
599
|
+
tsearch: {negation: true}
|
560
600
|
}
|
561
601
|
end
|
562
602
|
|
563
|
-
one_fish = Animal.create(:
|
564
|
-
two_fish = Animal.create(:
|
565
|
-
red_fish = Animal.create(:
|
566
|
-
blue_fish = Animal.create(:
|
603
|
+
one_fish = Animal.create(name: "one fish")
|
604
|
+
two_fish = Animal.create(name: "two fish")
|
605
|
+
red_fish = Animal.create(name: "red fish")
|
606
|
+
blue_fish = Animal.create(name: "blue fish")
|
567
607
|
|
568
608
|
Animal.with_name_matching("fish !red !blue") # => [one_fish, two_fish]
|
569
609
|
```
|
@@ -583,20 +623,20 @@ dictionary will be used.
|
|
583
623
|
class BoringTweet < ActiveRecord::Base
|
584
624
|
include PgSearch
|
585
625
|
pg_search_scope :kinda_matching,
|
586
|
-
:
|
587
|
-
:
|
588
|
-
:
|
626
|
+
against: :text,
|
627
|
+
using: {
|
628
|
+
tsearch: {dictionary: "english"}
|
589
629
|
}
|
590
630
|
pg_search_scope :literally_matching,
|
591
|
-
:
|
592
|
-
:
|
593
|
-
:
|
631
|
+
against: :text,
|
632
|
+
using: {
|
633
|
+
tsearch: {dictionary: "simple"}
|
594
634
|
}
|
595
635
|
end
|
596
636
|
|
597
|
-
sleepy = BoringTweet.create! :
|
598
|
-
sleeping = BoringTweet.create! :
|
599
|
-
sleeper = BoringTweet.create! :
|
637
|
+
sleepy = BoringTweet.create! text: "I snoozed my alarm for fourteen hours today. I bet I can beat that tomorrow! #sleepy"
|
638
|
+
sleeping = BoringTweet.create! text: "You know what I like? Sleeping. That's what. #enjoyment"
|
639
|
+
sleeper = BoringTweet.create! text: "Have you seen Woody Allen's movie entitled Sleeper? Me neither. #boycott"
|
600
640
|
|
601
641
|
BoringTweet.kinda_matching("sleeping") # => [sleepy, sleeping, sleeper]
|
602
642
|
BoringTweet.literally_matching("sleeping") # => [sleeping]
|
@@ -627,16 +667,16 @@ their numbers together.
|
|
627
667
|
class BigLongDocument < ActiveRecord::Base
|
628
668
|
include PgSearch
|
629
669
|
pg_search_scope :regular_search,
|
630
|
-
:
|
670
|
+
against: :text
|
631
671
|
|
632
672
|
pg_search_scope :short_search,
|
633
|
-
:
|
634
|
-
:
|
635
|
-
:
|
673
|
+
against: :text,
|
674
|
+
using: {
|
675
|
+
tsearch: {normalization: 2}
|
636
676
|
}
|
637
677
|
|
638
|
-
long = BigLongDocument.create!(:
|
639
|
-
short = BigLongDocument.create!(:
|
678
|
+
long = BigLongDocument.create!(text: "Four score and twenty years ago")
|
679
|
+
short = BigLongDocument.create!(text: "Four score")
|
640
680
|
|
641
681
|
BigLongDocument.regular_search("four score") #=> [long, short]
|
642
682
|
BigLongDocument.short_search("four score") #=> [short, long]
|
@@ -651,18 +691,18 @@ models containing any word in the search terms.
|
|
651
691
|
class Number < ActiveRecord::Base
|
652
692
|
include PgSearch
|
653
693
|
pg_search_scope :search_any_word,
|
654
|
-
:
|
655
|
-
:
|
656
|
-
:
|
694
|
+
against: :text,
|
695
|
+
using: {
|
696
|
+
tsearch: {any_word: true}
|
657
697
|
}
|
658
698
|
|
659
699
|
pg_search_scope :search_all_words,
|
660
|
-
:
|
700
|
+
against: :text
|
661
701
|
end
|
662
702
|
|
663
|
-
one = Number.create! :
|
664
|
-
two = Number.create! :
|
665
|
-
three = Number.create! :
|
703
|
+
one = Number.create! text: 'one'
|
704
|
+
two = Number.create! text: 'two'
|
705
|
+
three = Number.create! text: 'three'
|
666
706
|
|
667
707
|
Number.search_any_word('one two three') # => [one, two, three]
|
668
708
|
Number.search_all_words('one two three') # => []
|
@@ -677,17 +717,17 @@ but will not include it in the query's WHERE condition.
|
|
677
717
|
class Person < ActiveRecord::Base
|
678
718
|
include PgSearch
|
679
719
|
pg_search_scope :search,
|
680
|
-
:
|
681
|
-
:
|
682
|
-
:
|
683
|
-
:
|
720
|
+
against: :name,
|
721
|
+
using: {
|
722
|
+
tsearch: {any_word: true}
|
723
|
+
dmetaphone: {any_word: true, sort_only: true}
|
684
724
|
}
|
685
725
|
end
|
686
726
|
|
687
|
-
exact = Person.create!(:
|
688
|
-
one_exact_one_close = Person.create!(:
|
689
|
-
one_exact = Person.create!(:
|
690
|
-
one_close = Person.create!(:
|
727
|
+
exact = Person.create!(name: 'ash hines')
|
728
|
+
one_exact_one_close = Person.create!(name: 'ash heinz')
|
729
|
+
one_exact = Person.create!(name: 'ash smith')
|
730
|
+
one_close = Person.create!(name: 'leigh heinz')
|
691
731
|
|
692
732
|
Person.search('ash hines') # => [exact, one_exact_one_close, one_exact]
|
693
733
|
```
|
@@ -706,8 +746,8 @@ class Person < ActiveRecord::Base
|
|
706
746
|
using: {
|
707
747
|
tsearch: {
|
708
748
|
highlight: {
|
709
|
-
StartSel: '<
|
710
|
-
StopSel: '
|
749
|
+
StartSel: '<b>',
|
750
|
+
StopSel: '</b>',
|
711
751
|
MaxWords: 123,
|
712
752
|
MinWords: 456,
|
713
753
|
ShortWord: 4,
|
@@ -756,14 +796,14 @@ The following example shows how to use :dmetaphone.
|
|
756
796
|
class Word < ActiveRecord::Base
|
757
797
|
include PgSearch
|
758
798
|
pg_search_scope :that_sounds_like,
|
759
|
-
:
|
760
|
-
:
|
799
|
+
against: :spelling,
|
800
|
+
using: :dmetaphone
|
761
801
|
end
|
762
802
|
|
763
|
-
four = Word.create! :
|
764
|
-
far = Word.create! :
|
765
|
-
fur = Word.create! :
|
766
|
-
five = Word.create! :
|
803
|
+
four = Word.create! spelling: 'four'
|
804
|
+
far = Word.create! spelling: 'far'
|
805
|
+
fur = Word.create! spelling: 'fur'
|
806
|
+
five = Word.create! spelling: 'five'
|
767
807
|
|
768
808
|
Word.that_sounds_like("fir") # => [four, far, fur]
|
769
809
|
```
|
@@ -787,14 +827,14 @@ feature can be used.
|
|
787
827
|
class Website < ActiveRecord::Base
|
788
828
|
include PgSearch
|
789
829
|
pg_search_scope :kinda_spelled_like,
|
790
|
-
:
|
791
|
-
:
|
830
|
+
against: :name,
|
831
|
+
using: :trigram
|
792
832
|
end
|
793
833
|
|
794
|
-
yahooo = Website.create! :
|
795
|
-
yohoo = Website.create! :
|
796
|
-
gogle = Website.create! :
|
797
|
-
facebook = Website.create! :
|
834
|
+
yahooo = Website.create! name: "Yahooo!"
|
835
|
+
yohoo = Website.create! name: "Yohoo!"
|
836
|
+
gogle = Website.create! name: "Gogle"
|
837
|
+
facebook = Website.create! name: "Facebook"
|
798
838
|
|
799
839
|
Website.kinda_spelled_like("Yahoo!") # => [yahooo, yohoo]
|
800
840
|
```
|
@@ -813,23 +853,23 @@ class Vegetable < ActiveRecord::Base
|
|
813
853
|
include PgSearch
|
814
854
|
|
815
855
|
pg_search_scope :strictly_spelled_like,
|
816
|
-
:
|
817
|
-
:
|
818
|
-
:
|
819
|
-
:
|
856
|
+
against: :name,
|
857
|
+
using: {
|
858
|
+
trigram: {
|
859
|
+
threshold: 0.5
|
820
860
|
}
|
821
861
|
}
|
822
862
|
|
823
863
|
pg_search_scope :roughly_spelled_like,
|
824
|
-
:
|
825
|
-
:
|
826
|
-
:
|
827
|
-
:
|
864
|
+
against: :name,
|
865
|
+
using: {
|
866
|
+
trigram: {
|
867
|
+
threshold: 0.1
|
828
868
|
}
|
829
869
|
}
|
830
870
|
end
|
831
871
|
|
832
|
-
cauliflower = Vegetable.create! :
|
872
|
+
cauliflower = Vegetable.create! name: "cauliflower"
|
833
873
|
|
834
874
|
Vegetable.roughly_spelled_like("couliflower") # => [cauliflower]
|
835
875
|
Vegetable.strictly_spelled_like("couliflower") # => [cauliflower]
|
@@ -851,11 +891,11 @@ class Image < ActiveRecord::Base
|
|
851
891
|
include PgSearch
|
852
892
|
|
853
893
|
pg_search_scope :combined_search,
|
854
|
-
:
|
855
|
-
:
|
856
|
-
:
|
857
|
-
:
|
858
|
-
:
|
894
|
+
against: [:file_name, :short_description, :long_description]
|
895
|
+
using: {
|
896
|
+
tsearch: { dictionary: 'english' },
|
897
|
+
trigram: {
|
898
|
+
only: [:file_name, :short_description]
|
859
899
|
}
|
860
900
|
}
|
861
901
|
|
@@ -885,13 +925,13 @@ must be installed before this feature can be used.
|
|
885
925
|
class SpanishQuestion < ActiveRecord::Base
|
886
926
|
include PgSearch
|
887
927
|
pg_search_scope :gringo_search,
|
888
|
-
:
|
889
|
-
:
|
928
|
+
against: :word,
|
929
|
+
ignoring: :accents
|
890
930
|
end
|
891
931
|
|
892
|
-
what = SpanishQuestion.create(:
|
893
|
-
how_many = SpanishQuestion.create(:
|
894
|
-
how = SpanishQuestion.create(:
|
932
|
+
what = SpanishQuestion.create(word: "Qué")
|
933
|
+
how_many = SpanishQuestion.create(word: "Cuánto")
|
934
|
+
how = SpanishQuestion.create(word: "Cómo")
|
895
935
|
|
896
936
|
SpanishQuestion.gringo_search("Que") # => [what]
|
897
937
|
SpanishQuestion.gringo_search("Cüåñtô") # => [how_many]
|
@@ -928,8 +968,8 @@ To use this functionality you'll need to do a few things:
|
|
928
968
|
|
929
969
|
```ruby
|
930
970
|
pg_search_scope :fast_content_search,
|
931
|
-
:
|
932
|
-
:
|
971
|
+
against: :content,
|
972
|
+
using: {
|
933
973
|
dmetaphone: {
|
934
974
|
tsvector_column: 'tsvector_content_dmetaphone'
|
935
975
|
},
|
@@ -940,13 +980,6 @@ To use this functionality you'll need to do a few things:
|
|
940
980
|
trigram: {} # trigram does not use tsvectors
|
941
981
|
}
|
942
982
|
```
|
943
|
-
* You cannot dump a `tsvector` column to `schema.rb`. Instead, you need to switch to using the native PostgreSQL SQL format schema dump.
|
944
|
-
In your `config/application.rb` you should set
|
945
|
-
|
946
|
-
config.active_record.schema_format = :sql
|
947
|
-
|
948
|
-
Read more about it here: http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps
|
949
|
-
|
950
983
|
|
951
984
|
Please note that the :against column is only used when the tsvector_column is
|
952
985
|
not present for the search type.
|
@@ -957,26 +990,26 @@ It's possible to search against more than one tsvector at a time. This could be
|
|
957
990
|
|
958
991
|
```ruby
|
959
992
|
pg_search_scope :search_title,
|
960
|
-
:
|
961
|
-
:
|
962
|
-
:
|
963
|
-
:
|
993
|
+
against: :title,
|
994
|
+
using: {
|
995
|
+
tsearch: {
|
996
|
+
tsvector_column: "title_tsvector"
|
964
997
|
}
|
965
998
|
}
|
966
999
|
|
967
1000
|
pg_search_scope :search_body,
|
968
|
-
:
|
969
|
-
:
|
970
|
-
:
|
971
|
-
:
|
1001
|
+
against: :body,
|
1002
|
+
using: {
|
1003
|
+
tsearch: {
|
1004
|
+
tsvector_column: "body_tsvector"
|
972
1005
|
}
|
973
1006
|
}
|
974
1007
|
|
975
1008
|
pg_search_scope :search_title_and_body,
|
976
|
-
:
|
977
|
-
:
|
978
|
-
:
|
979
|
-
:
|
1009
|
+
against: [:title, :body],
|
1010
|
+
using: {
|
1011
|
+
tsearch: {
|
1012
|
+
tsvector_column: ["title_tsvector", "body_tsvector"]
|
980
1013
|
}
|
981
1014
|
}
|
982
1015
|
```
|
@@ -991,9 +1024,9 @@ can pass a :ranked_by option to pg_search_scope.
|
|
991
1024
|
|
992
1025
|
```ruby
|
993
1026
|
pg_search_scope :search_by_tsearch_but_rank_by_trigram,
|
994
|
-
:
|
995
|
-
:
|
996
|
-
:
|
1027
|
+
against: :title,
|
1028
|
+
using: [:tsearch],
|
1029
|
+
ranked_by: ":trigram"
|
997
1030
|
```
|
998
1031
|
|
999
1032
|
Note that :ranked_by using a String to represent the ranking expression. This
|
@@ -1003,10 +1036,10 @@ expressions.
|
|
1003
1036
|
|
1004
1037
|
```ruby
|
1005
1038
|
# Weighted ranking to balance multiple approaches
|
1006
|
-
:
|
1039
|
+
ranked_by: ":dmetaphone + (0.25 * :trigram)"
|
1007
1040
|
|
1008
1041
|
# A more complex example, where books.num_pages is an integer column in the table itself
|
1009
|
-
:
|
1042
|
+
ranked_by: "(books.num_pages * :trigram) + (:tsearch / 2.0)"
|
1010
1043
|
```
|
1011
1044
|
|
1012
1045
|
#### :order_within_rank (Breaking ties)
|
@@ -1038,8 +1071,8 @@ descending by updated_at, to rank the most recently updated records first.
|
|
1038
1071
|
|
1039
1072
|
```ruby
|
1040
1073
|
pg_search_scope :search_and_break_ties_by_latest_update,
|
1041
|
-
:
|
1042
|
-
:
|
1074
|
+
against: [:title, :content],
|
1075
|
+
order_within_rank: "blog_posts.updated_at DESC"
|
1043
1076
|
```
|
1044
1077
|
|
1045
1078
|
#### PgSearch#pg_search_rank (Reading a record's rank as a Float)
|