chewy 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -8
  3. data/Appraisals +8 -0
  4. data/CHANGELOG.md +33 -6
  5. data/Gemfile +6 -4
  6. data/README.md +240 -111
  7. data/gemfiles/rails.4.2.activerecord.gemfile +1 -0
  8. data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +1 -0
  9. data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +1 -0
  10. data/gemfiles/sequel.4.23.gemfile +13 -0
  11. data/lib/chewy.rb +24 -11
  12. data/lib/chewy/config.rb +4 -4
  13. data/lib/chewy/index.rb +1 -1
  14. data/lib/chewy/index/settings.rb +1 -1
  15. data/lib/chewy/query.rb +43 -4
  16. data/lib/chewy/railtie.rb +2 -2
  17. data/lib/chewy/rake_helper.rb +62 -0
  18. data/lib/chewy/rspec/update_index.rb +3 -3
  19. data/lib/chewy/strategy.rb +6 -0
  20. data/lib/chewy/strategy/active_job.rb +28 -0
  21. data/lib/chewy/strategy/atomic.rb +1 -1
  22. data/lib/chewy/strategy/sidekiq.rb +3 -1
  23. data/lib/chewy/type.rb +2 -1
  24. data/lib/chewy/type/adapter/active_record.rb +9 -2
  25. data/lib/chewy/type/adapter/base.rb +6 -0
  26. data/lib/chewy/type/adapter/mongoid.rb +7 -1
  27. data/lib/chewy/type/adapter/orm.rb +1 -1
  28. data/lib/chewy/type/adapter/sequel.rb +125 -0
  29. data/lib/chewy/type/mapping.rb +26 -1
  30. data/lib/chewy/type/observe.rb +40 -17
  31. data/lib/chewy/version.rb +1 -1
  32. data/lib/sequel/plugins/chewy_observe.rb +71 -0
  33. data/lib/tasks/chewy.rake +19 -61
  34. data/spec/chewy/config_spec.rb +9 -5
  35. data/spec/chewy/fields/base_spec.rb +21 -7
  36. data/spec/chewy/index/actions_spec.rb +5 -5
  37. data/spec/chewy/query_spec.rb +69 -0
  38. data/spec/chewy/runtime_spec.rb +1 -1
  39. data/spec/chewy/strategy/active_job_spec.rb +49 -0
  40. data/spec/chewy/strategy_spec.rb +2 -2
  41. data/spec/chewy/type/adapter/sequel_spec.rb +46 -0
  42. data/spec/chewy/type/import_spec.rb +4 -2
  43. data/spec/chewy/type/mapping_spec.rb +19 -0
  44. data/spec/chewy/type/observe_spec.rb +43 -14
  45. data/spec/chewy_spec.rb +2 -3
  46. data/spec/spec_helper.rb +6 -3
  47. data/spec/support/active_record.rb +5 -8
  48. data/spec/support/mongoid.rb +5 -8
  49. data/spec/support/sequel.rb +69 -0
  50. metadata +14 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a311bdd3957835909c81ba57886bba5fbebebbef
4
- data.tar.gz: 0011b212e985166c040bb195ec3dc0214b797ab5
3
+ metadata.gz: 465b8f0c2bff702e61235bbd9b6782f3f57296e6
4
+ data.tar.gz: 60827a551d9b4338ee87a91c346b84cfbcca6aa2
5
5
  SHA512:
6
- metadata.gz: 2727a488bbaefa2b0d9bd47da643a83e72882bfe3da41e4eda9e7e59df37fb72ad0343273594ae7dfbfbb8d4f84534d63867038b6fd8de667aca4eb0126c34a3
7
- data.tar.gz: 6e54cfb1362cc06ff500ee01eb24c809c54c590b6390e20bfd45db4bb61c0c403ea3afd93b6dd3ef23bb53336efb157bd9c4cbca2aad9065db019a6693e84530
6
+ metadata.gz: e0efb611f827fa291ea9f3765d14e50450e6787f0541e9c04f034d79e20189cdb8dd718e2c8c8074e7736ac3575018e13fe9317f880d7b6d0429ac1ab060e6b2
7
+ data.tar.gz: 0270d359d7831c3f1c0217369f32d5017c7b90e7871780a5e79f7945414c7a3aaadf39f1505ab85c7a3c61a1f2fbb28ae49c183034f43c12d1ed065cf66e9acf
@@ -1,10 +1,11 @@
1
1
  language: ruby
2
+ sudo: false
2
3
  services:
3
4
  - mongodb
4
5
  rvm:
5
- - 2.0.0
6
- - 2.1.5
7
- - 2.2.0
6
+ - 2.0
7
+ - 2.1
8
+ - 2.2
8
9
  # - rbx
9
10
  gemfile:
10
11
  - gemfiles/rails.3.2.activerecord.gemfile
@@ -28,15 +29,16 @@ gemfile:
28
29
  - gemfiles/rails.4.2.mongoid.gemfile
29
30
  - gemfiles/rails.4.2.mongoid.kaminari.gemfile
30
31
  - gemfiles/rails.4.2.mongoid.will_paginate.gemfile
32
+ - gemfiles/sequel.4.23.gemfile
31
33
  matrix:
32
34
  exclude:
33
- - rvm: 2.2.0
35
+ - rvm: 2.2
34
36
  gemfile: gemfiles/rails.3.2.activerecord.gemfile
35
- - rvm: 2.2.0
37
+ - rvm: 2.2
36
38
  gemfile: gemfiles/rails.3.2.activerecord.kaminari.gemfile
37
- - rvm: 2.2.0
39
+ - rvm: 2.2
38
40
  gemfile: gemfiles/rails.3.2.activerecord.will_paginate.gemfile
39
41
  before_install:
40
- - curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.5.2.tar.gz | tar xz -C /tmp
42
+ - curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.7.2.tar.gz | tar xz -C /tmp
41
43
  before_script:
42
- - TEST_CLUSTER_COMMAND="/tmp/elasticsearch-1.5.2/bin/elasticsearch" rake elasticsearch:start
44
+ - TEST_CLUSTER_COMMAND="/tmp/elasticsearch-1.7.2/bin/elasticsearch" rake elasticsearch:start
data/Appraisals CHANGED
@@ -2,6 +2,7 @@
2
2
  appraise "rails.#{version}.activerecord" do
3
3
  gem 'activerecord', "~> #{version}.0"
4
4
  gem 'activesupport', "~> #{version}.0"
5
+ gem 'activejob', "~> #{version}.0" if version >= '4.2'
5
6
  gem 'resque', require: false
6
7
  gem 'sidekiq', require: false
7
8
  end
@@ -9,12 +10,14 @@
9
10
  appraise "rails.#{version}.activerecord.kaminari" do
10
11
  gem 'activerecord', "~> #{version}.0"
11
12
  gem 'activesupport', "~> #{version}.0"
13
+ gem 'activejob', "~> #{version}.0" if version >= '4.2'
12
14
  gem 'kaminari', '0.16.3', require: false
13
15
  end
14
16
 
15
17
  appraise "rails.#{version}.activerecord.will_paginate" do
16
18
  gem 'activerecord', "~> #{version}.0"
17
19
  gem 'activesupport', "~> #{version}.0"
20
+ gem 'activejob', "~> #{version}.0" if version >= '4.2'
18
21
  gem 'will_paginate', require: false
19
22
  end
20
23
  end
@@ -39,3 +42,8 @@ end
39
42
  gem 'will_paginate', require: false
40
43
  end
41
44
  end
45
+
46
+ appraise "sequel.4.23" do
47
+ gem 'sequel', "~> 4.23.0"
48
+ gem 'activesupport', '~> 4.2.0'
49
+ end
@@ -1,5 +1,32 @@
1
1
  # master
2
2
 
3
+ # Version 0.8.2
4
+
5
+ ## Changes
6
+
7
+ * ActiveJob strategy by @mkcode
8
+
9
+ * Async strategies tweak (@AndreySavelyev)
10
+
11
+ * GeoPoint readme (@joonty)
12
+
13
+ * Multiple grammar fixes and code improvements (@biow0lf)
14
+
15
+ * Named aggregations by @caldwecr
16
+
17
+ * Sequel adapter by @jirutka
18
+
19
+ * Rake helper methods extracted (@caldwecr, @jirutka)
20
+
21
+ * Multiple grammar fixes (@henrebotha)
22
+
23
+ * Ability to pass a proc to `update_index` to define updating index dynamically (@SeTeM)
24
+
25
+
26
+ ## Bugfixes
27
+
28
+ * Fixed transport logger and tracer configuration
29
+
3
30
  # Version 0.8.1
4
31
 
5
32
  ## Bugfixes
@@ -18,7 +45,7 @@
18
45
 
19
46
  * Added `.script_fields` chainable method to query (@ka8725)
20
47
 
21
- * `update_index` mocha support (@lardawge)
48
+ * `update_index` matcher mocha support (@lardawge)
22
49
 
23
50
  * `:resque` async strategy
24
51
 
@@ -90,7 +117,7 @@
90
117
 
91
118
  * Multiple enhancements by @DNNX
92
119
 
93
- * Added `script_fields` to search crteria (@ka8725)
120
+ * Added `script_fields` to search criteria (@ka8725)
94
121
 
95
122
  * ORM adapters now completely relies on the default scope. This means every scope or objects passed to import are merged with default scope so basically there is no need to define `delete_if` block. Default scope strongly restricts objects which may land in the current index.
96
123
 
@@ -269,13 +296,13 @@
269
296
 
270
297
  # Version 0.4.0
271
298
 
272
- * Changed `update_index` matcher behavior. Now it compare array attributes position-independantly.
299
+ * Changed `update_index` matcher behavior. Now it compare array attributes position-independently.
273
300
 
274
301
  * Search aggregations API support (@arion).
275
302
 
276
303
  * Chewy::Query#facets called without params performs the request and returns facets.
277
304
 
278
- * Added `Type.template` dsl method for root objects dynamic templates definition. See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
305
+ * Added `Type.template` DSL method for root objects dynamic templates definition. See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
279
306
 
280
307
  * ActiveRecord adapter custom `primary_key` support (@matthee).
281
308
 
@@ -414,8 +441,8 @@
414
441
 
415
442
  # Version 0.0.1
416
443
 
417
- * Query dsl
444
+ * Query DSL
418
445
 
419
- * Basic index hadling
446
+ * Basic index handling
420
447
 
421
448
  * Initial version
data/Gemfile CHANGED
@@ -2,14 +2,16 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'activerecord'
5
+ # gem 'activerecord'
6
6
  # gem 'mongoid'
7
+ # gem 'sequel'
7
8
 
8
9
  # gem 'kaminari', require: false
9
- # gem 'will_pagnate', require: false
10
+ # gem 'will_paginate', require: false
10
11
 
11
- gem 'resque', require: false
12
- gem 'sidekiq', require: false
12
+ # gem 'resque', require: false
13
+ # gem 'sidekiq', require: false
14
+ # gem 'activejob', require: false
13
15
 
14
16
  group :test do
15
17
  gem 'guard'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/chewy.svg)](http://badge.fury.io/rb/chewy)
2
- [![Build Status](https://travis-ci.org/toptal/chewy.png)](https://travis-ci.org/toptal/chewy)
3
- [![Code Climate](https://codeclimate.com/github/toptal/chewy.png)](https://codeclimate.com/github/toptal/chewy)
2
+ [![Build Status](https://travis-ci.org/toptal/chewy.svg)](https://travis-ci.org/toptal/chewy)
3
+ [![Code Climate](https://codeclimate.com/github/toptal/chewy.svg)](https://codeclimate.com/github/toptal/chewy)
4
4
  [![Inline docs](http://inch-ci.org/github/toptal/chewy.svg?branch=master)](http://inch-ci.org/github/toptal/chewy)
5
5
 
6
6
  <p align="right">Sponsored by</p>
@@ -8,25 +8,28 @@
8
8
 
9
9
  # Chewy
10
10
 
11
- Chewy is ODM and wrapper for official elasticsearch client (https://github.com/elasticsearch/elasticsearch-ruby)
11
+ Chewy is an ODM and wrapper for [the official Elasticsearch client](https://github.com/elasticsearch/elasticsearch-ruby).
12
12
 
13
- ## Why chewy?
13
+ ## Why Chewy?
14
14
 
15
- * Multi-model indexes.
15
+ * Multi-model indices.
16
16
 
17
- Index classes are independent from ORM/ODM models. Now implementing, e.g. cross-model autocomplete is much easier. You can just define index and work with it in object-oriented style. You can define several types for index - one per indexed model.
17
+ Index classes are independent from ORM/ODM models. Now, implementing e.g. cross-model autocomplete is much easier. You can just define the index and work with it in an object-oriented style. You can define several types for index - one per indexed model.
18
18
 
19
19
  * Every index is observable by all the related models.
20
20
 
21
- Most of the indexed models are related to other and sometimes it is nessesary to denormalize this related data and put at the same object. For example, you need to index array of tags with article together. Chewy allows you to specify updatable index for every model separately. So, corresponding articles will be reindexed on any tag update.
21
+ Most of the indexed models are related to other and sometimes it is necessary to denormalize this related data and put at the same object. For example, you need to index an array of tags together with an article. Chewy allows you to specify an updateable index for every model separately - so corresponding articles will be reindexed on any tag update.
22
22
 
23
23
  * Bulk import everywhere.
24
24
 
25
- Chewy utilizes bulk ES API for full reindexing or index updates. Also it uses atomic updates concept. All the changed objects are collected inside the atomic block and index is updated once at the end of it with all the collected object. See `Chewy.strategy(:atomic)` for more details.
25
+ Chewy utilizes the bulk ES API for full reindexing or index updates. It also uses atomic updates. All the changed objects are collected inside the atomic block and the index is updated once at the end with all the collected objects. See `Chewy.strategy(:atomic)` for more details.
26
26
 
27
27
  * Powerful querying DSL.
28
28
 
29
- Chewy has AR-style query DSL. It is chainable, mergable and lazy. So you can produce queries in the most efficient way. Also it has object-oriented query and filter builders.
29
+ Chewy has an ActiveRecord-style query DSL. It is chainable, mergeable and lazy, so you can produce queries in the most efficient way. It also has object-oriented query and filter builders.
30
+
31
+ * Support for ActiveRecord, [Mongoid](https://github.com/mongoid/mongoid) and [Sequel](https://github.com/jeremyevans/sequel).
32
+
30
33
 
31
34
  ## Installation
32
35
 
@@ -46,9 +49,9 @@ Or install it yourself as:
46
49
 
47
50
  ### Client settings
48
51
 
49
- There are 2 ways to configure Chewy client: `Chewy.settings` hash and `chewy.yml`
52
+ There are two ways to configure the Chewy client: the `Chewy.settings` hash and `chewy.yml`
50
53
 
51
- You can create this file manually or run `rails g chewy:install` to do that with yaml way
54
+ You can create this file manually or run `rails g chewy:install`.
52
55
 
53
56
  ```ruby
54
57
  # config/initializers/chewy.rb
@@ -65,17 +68,17 @@ development:
65
68
  host: 'localhost:9200'
66
69
  ```
67
70
 
68
- The result config merges both hashes. Client options are passed as is to Elasticsearch::Transport::Client except the `:prefix` - it is used internally by chewy to create prefixed index names:
71
+ The resulting config merges both hashes. Client options are passed as is to `Elasticsearch::Transport::Client` except for the `:prefix`, which is used internally by Chewy to create prefixed index names:
69
72
 
70
73
  ```ruby
71
74
  Chewy.settings = {prefix: 'test'}
72
75
  UsersIndex.index_name # => 'test_users'
73
76
  ```
74
77
 
75
- Also logger might be set explicitly:
78
+ The logger may be set explicitly:
76
79
 
77
80
  ```ruby
78
- Chewy.logger = Logger.new
81
+ Chewy.logger = Logger.new(STDOUT)
79
82
  ```
80
83
 
81
84
  See [config.rb](lib/chewy/config.rb) for more details.
@@ -106,7 +109,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
106
109
  class UsersIndex < Chewy::Index
107
110
  define_type User.active.includes(:country, :badges, :projects) do
108
111
  field :first_name, :last_name # multiple fields without additional options
109
- field :email, analyzer: 'email' # elasticsearch-related options
112
+ field :email, analyzer: 'email' # Elasticsearch-related options
110
113
  field :country, value: ->(user) { user.country.name } # custom value proc
111
114
  field :badges, value: ->(user) { user.badges.map(&:name) } # passing array values to index
112
115
  field :projects do # the same block syntax for multi_field, if `:type` is specified
@@ -122,9 +125,9 @@ See [config.rb](lib/chewy/config.rb) for more details.
122
125
  end
123
126
  ```
124
127
 
125
- Mapping definitions - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping.html
128
+ [See here for mapping definitions](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping.html).
126
129
 
127
- 4. Add some index- and type-related settings. Analyzers repositories might be used as well. See `Chewy::Index.settings` docs for details:
130
+ 4. Add some index- and type-related settings. Analyzer repositories might be used as well. See `Chewy::Index.settings` docs for details:
128
131
 
129
132
  ```ruby
130
133
  class UsersIndex < Chewy::Index
@@ -149,7 +152,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
149
152
  field :title
150
153
  field :description
151
154
  end
152
- field :about_translations, type: 'object' # pass object type explicitely if necessary
155
+ field :about_translations, type: 'object' # pass object type explicitly if necessary
153
156
  field :rating, type: 'integer'
154
157
  field :created, type: 'date', include_in_all: false,
155
158
  value: ->{ created_at }
@@ -158,16 +161,16 @@ See [config.rb](lib/chewy/config.rb) for more details.
158
161
  end
159
162
  ```
160
163
 
161
- Index settings - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-update-settings.html
162
- Root object settings - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-root-object-type.html
164
+ [See index settings here](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-update-settings.html).
165
+ [See root object settings here](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-root-object-type.html).
163
166
 
164
167
  See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
165
168
 
166
- 5. Add model observing code
169
+ 5. Add model-observing code
167
170
 
168
171
  ```ruby
169
172
  class User < ActiveRecord::Base
170
- update_index('users#user') { self } # specifying index, type and backreference
173
+ update_index('users#user') { self } # specifying index, type and back-reference
171
174
  # for updating after user save or destroy
172
175
  end
173
176
 
@@ -178,7 +181,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
178
181
  end
179
182
 
180
183
  class Project < ActiveRecord::Base
181
- update_index('users#user') { user if user.active? } # you can return even `nil` from the backreference
184
+ update_index('users#user') { user if user.active? } # you can return even `nil` from the back-reference
182
185
  end
183
186
 
184
187
  class Badge < ActiveRecord::Base
@@ -187,16 +190,22 @@ See [config.rb](lib/chewy/config.rb) for more details.
187
190
  update_index('users') { users } # if index has only one type
188
191
  # there is no need to specify updated type
189
192
  end
193
+
194
+ class Book < ActiveRecord::Base
195
+ update_index(->(book) {"books#book_#{book.language}"}) { self } # dynamic index and type with proc.
196
+ # For book with language == "en"
197
+ # this code will generate `books#book_en`
198
+ end
190
199
  ```
191
200
 
192
- Also, you can use second argument for method name passing:
201
+ Also, you can use the second argument for method name passing:
193
202
 
194
203
  ```ruby
195
204
  update_index('users#user', :self)
196
205
  update_index('users#user', :users)
197
206
  ```
198
207
 
199
- In case of belongs_to association you may need to update both associated objects, previous and current:
208
+ In the case of a belongs_to association you may need to update both associated objects, previous and current:
200
209
 
201
210
  ```ruby
202
211
  class City < ActiveRecord::Base
@@ -212,9 +221,67 @@ See [config.rb](lib/chewy/config.rb) for more details.
212
221
  end
213
222
  ```
214
223
 
224
+ You can observe Sequel models in the same way as ActiveRecord:
225
+
226
+ ```ruby
227
+ class User < Sequel::Model
228
+ update_index('users#user') { self }
229
+ end
230
+ ```
231
+
232
+ However, to make it work, you must load the chewy plugin into Sequel model:
233
+
234
+ ```ruby
235
+ Sequel::Model.plugin :chewy_observe # for all models, or...
236
+ User.plugin :chewy_observe # just for User
237
+ ```
238
+
239
+ ### Multi (nested) and object field types
240
+
241
+ To define an objects field you can simply nest fields in the DSL:
242
+
243
+ ```ruby
244
+ field :projects do
245
+ field :title
246
+ field :description
247
+ end
248
+ ```
249
+
250
+ This will automatically set the type or root field to `object`. You may also specify `type: 'objects'` explicitly.
251
+
252
+ To define a multi field you have to specify any type except for `object` or `nested` in the root field:
253
+
254
+ ```ruby
255
+ field :full_name, type: 'string', value: ->{ full_name.strip } do
256
+ field :ordered, analyzer: `ordered`
257
+ field :untouched, index: 'not_analyzed'
258
+ end
259
+ ```
260
+
261
+ The `value:` option for internal fields would no longer be effective.
262
+
263
+ ### Geo Point fields
264
+
265
+ You can use [Elasticsearch's geo mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-geo-point-type.html) with the `geo_point` field type, allowing you to query, filter and order by latitude and longitude. You can use the following hash format:
266
+
267
+ ```ruby
268
+ field :coordinates, type: 'geo_point', value: ->{ {lat: latitude, lon: longitude} }
269
+ ```
270
+
271
+ or by using nested fields:
272
+
273
+ ```ruby
274
+ field :coordinates, type: 'geo_point' do
275
+ field :lat, value: ->{ latitude }
276
+ field :long, value: ->{ longitude }
277
+ end
278
+ ```
279
+
280
+ See the section on *Script fields* for details on calculating distance in a search.
281
+
215
282
  ### Crutches™ technology
216
283
 
217
- Assume you are defining index like this (product has_many categories through product_categories):
284
+ Assume you are defining your index like this (product has_many categories through product_categories):
218
285
 
219
286
  ```ruby
220
287
  class ProductsIndex < Chewy::Index
@@ -225,7 +292,7 @@ class ProductsIndex < Chewy::Index
225
292
  end
226
293
  ```
227
294
 
228
- Then chewy reindexing flow would be look like following pseudo-code (even in mongoid):
295
+ Then the Chewy reindexing flow would look like the following pseudo-code (even in Mongoid):
229
296
 
230
297
  ```ruby
231
298
  Product.includes(:categories).find_in_batches(1000) do |batch|
@@ -237,9 +304,9 @@ Product.includes(:categories).find_in_batches(1000) do |batch|
237
304
  end
238
305
  ```
239
306
 
240
- But in rails 4.1 and 4.2 you may face with slow associations problem (take a look on https://github.com/rails/rails/pull/19423) also, there might be really complicated cases when associations are not applicable.
307
+ But in Rails 4.1 and 4.2 you may face a problem with slow associations (take a look at https://github.com/rails/rails/pull/19423). Also, there might be really complicated cases when associations are not applicable.
241
308
 
242
- Then you are able to replace rails associations with Chewy Crutches™ technology:
309
+ Then you can replace Rails associations with Chewy Crutches™ technology:
243
310
 
244
311
  ```ruby
245
312
  class ProductsIndex < Chewy::Index
@@ -249,7 +316,7 @@ class ProductsIndex < Chewy::Index
249
316
  data = ProductCategory.joins(:category).where(product_id: collection.map(&:id)).pluck(:product_id, 'categories.name')
250
317
  # then we have to convert fetched data to appropriate format
251
318
  # this will return our data in structure like:
252
- # {123 => ['seweets', 'juices'], 456 => ['meat']}
319
+ # {123 => ['sweets', 'juices'], 456 => ['meat']}
253
320
  data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
254
321
  end
255
322
 
@@ -260,7 +327,7 @@ class ProductsIndex < Chewy::Index
260
327
  end
261
328
  ```
262
329
 
263
- And example flow would be look like this:
330
+ An example flow would look like this:
264
331
 
265
332
  ```ruby
266
333
  Product.includes(:categories).find_in_batches(1000) do |batch|
@@ -274,11 +341,11 @@ Product.includes(:categories).find_in_batches(1000) do |batch|
274
341
  end
275
342
  ```
276
343
 
277
- So Chewy Crutches™ technology is able to increase your indexing performance in some cases up to 100 times or even more depending on your associations complexity.
344
+ So Chewy Crutches™ technology is able to increase your indexing performance in some cases up to a hundredfold or even more depending on your associations complexity.
278
345
 
279
346
  ### Types access
280
347
 
281
- You are able to access index-defined types with the following API:
348
+ You can access index-defined types with the following API:
282
349
 
283
350
  ```ruby
284
351
  UsersIndex::User # => UsersIndex::User
@@ -291,7 +358,7 @@ UsersIndex.type_names # => ['user']
291
358
  ### Index manipulation
292
359
 
293
360
  ```ruby
294
- UsersIndex.delete # destroy index if exists
361
+ UsersIndex.delete # destroy index if it exists
295
362
  UsersIndex.delete!
296
363
 
297
364
  UsersIndex.create
@@ -312,7 +379,7 @@ UsersIndex.import user: User.where('rating > 100') # import only active users to
312
379
  UsersIndex.reset! # purges index and imports default data for all types
313
380
  ```
314
381
 
315
- Also if passed user is `#destroyed?`, or satisfy `delete_if` type option, or specified id does not exists in the database, import will perform delete from index action for this object.
382
+ If the passed user is `#destroyed?`, or satisfies a `delete_if` type option, or the specified id does not exist in the database, import will perform delete from index action for this object.
316
383
 
317
384
  ```ruby
318
385
  define_type User, delete_if: :deleted_at
@@ -338,18 +405,13 @@ class CitiesIndex < Chewy::Index
338
405
  end
339
406
  ```
340
407
 
341
- If you'll perform something like `City.first.save!` you'll get
342
- UndefinedUpdateStrategy exception instead of normal object saving
343
- and index update. This exception forces you to choose appropriate
344
- update strategy for current context.
408
+ If you do something like `City.first.save!` you'll get an UndefinedUpdateStrategy exception instead of the object saving and index updating. This exception forces you to choose an appropriate update strategy for the current context.
345
409
 
346
- If you want to return behavior was before 0.7.0 - just set
347
- `Chewy.root_strategy = :bypass`.
410
+ If you want to return to the pre-0.7.0 behavior - just set `Chewy.root_strategy = :bypass`.
348
411
 
349
412
  #### `:atomic`
350
413
 
351
- The main strategy here is `:atomic`. Assume you have to update a
352
- lot of records in db.
414
+ The main strategy here is `:atomic`. Assume you have to update a lot of records in the db.
353
415
 
354
416
  ```ruby
355
417
  Chewy.strategy(:atomic) do
@@ -357,15 +419,11 @@ Chewy.strategy(:atomic) do
357
419
  end
358
420
  ```
359
421
 
360
- Using this strategy delays index update request until the end of
361
- block. Updated records are aggregated and index update happens with
362
- bulk API. So this strategy is highly optimized.
422
+ Using this strategy delays the index update request until the end of the block. Updated records are aggregated and the index update happens with the bulk API. So this strategy is highly optimized.
363
423
 
364
424
  #### `:resque`
365
425
 
366
- Does the same thing as `:atomic`, but in async way using resque.
367
- Default queue name is `chewy`.
368
- Patch `Chewy::Strategy::Resque::Worker` for index updates improving.
426
+ This does the same thing as `:atomic`, but asynchronously using resque. The default queue name is `chewy`. Patch `Chewy::Strategy::Resque::Worker` for index updates improving.
369
427
 
370
428
  ```ruby
371
429
  Chewy.strategy(:resque) do
@@ -375,8 +433,7 @@ end
375
433
 
376
434
  #### `:sidekiq`
377
435
 
378
- Does the same thing as `:atomic`, but in async way using sidekiq.
379
- Patch `Chewy::Strategy::Sidekiq::Worker` for index updates improving.
436
+ This does the same thing as `:atomic`, but asynchronously using sidekiq. Patch `Chewy::Strategy::Sidekiq::Worker` for index updates improving.
380
437
 
381
438
  ```ruby
382
439
  Chewy.strategy(:sidekiq) do
@@ -384,10 +441,19 @@ Chewy.strategy(:sidekiq) do
384
441
  end
385
442
  ```
386
443
 
444
+ #### `:active_job`
445
+
446
+ This does the same thing as `:atomic`, but using ActiveJob. This will inherit the ActiveJob configuration settings including the `active_job.queue_adapter` setting for the environment. Patch `Chewy::Strategy::ActiveJob::Worker` for index updates improving.
447
+
448
+ ```ruby
449
+ Chewy.strategy(:active_job) do
450
+ City.popular.map(&:do_some_update_action!)
451
+ end
452
+ ```
453
+
387
454
  #### `:urgent`
388
455
 
389
- Next strategy is convenient if you are going to update documents in
390
- index one-by-one.
456
+ The following strategy is convenient if you are going to update documents in your index one by one.
391
457
 
392
458
  ```ruby
393
459
  Chewy.strategy(:urgent) do
@@ -395,11 +461,9 @@ Chewy.strategy(:urgent) do
395
461
  end
396
462
  ```
397
463
 
398
- This code would perform `City.popular.count` requests for ES
399
- documents update.
464
+ This code would perform `City.popular.count` requests for ES documents update.
400
465
 
401
- Seems to be convenient for usage in e.g. rails console with
402
- non-block notation:
466
+ It is convenient for use in e.g. the Rails console with non-block notation:
403
467
 
404
468
  ```ruby
405
469
  > Chewy.strategy(:urgent)
@@ -408,12 +472,11 @@ non-block notation:
408
472
 
409
473
  #### `:bypass`
410
474
 
411
- Bypass strategy simply silences index updates.
475
+ The bypass strategy simply silences index updates.
412
476
 
413
477
  #### Nesting
414
478
 
415
- Strategies are designed to allow nesting, so it is possible
416
- to redefine it for nested contexts.
479
+ Strategies are designed to allow nesting, so it is possible to redefine it for nested contexts.
417
480
 
418
481
  ```ruby
419
482
  Chewy.strategy(:atomic) do
@@ -441,22 +504,19 @@ Chewy.strategy.pop
441
504
  city3.do_update! # index updated again
442
505
  ```
443
506
 
444
- #### Designing own strategies
507
+ #### Designing your own strategies
445
508
 
446
- See [strategy/base.rb](lib/chewy/strategy/base.rb) for more details.
447
- See [strategy/atomic.rb](lib/chewy/strategy/atomic.rb) for example.
509
+ See [strategy/base.rb](lib/chewy/strategy/base.rb) for more details. See [strategy/atomic.rb](lib/chewy/strategy/atomic.rb) for an example.
448
510
 
449
511
  ### Rails application strategies integration
450
512
 
451
- There is a couple of pre-defined strategies for your rails application. At first, rails console uses `:urgent` strategy by default, except the sandbox case. When you are running sandbox it switches to `bypass` strategy to avoid index polluting.
452
-
453
- Also migrations are wrapped with `:bypass` strategy. Because the main behavor implies that indexes are resetted after migration, so there is no need for extra index updates.
454
- Also indexing might be broken during migrations because of the outdated schema.
513
+ There are a couple of predefined strategies for your Rails application. Initially, the Rails console uses the `:urgent` strategy by default, except in the sandbox case. When you are running sandbox it switches to the `:bypass` strategy to avoid polluting the index.
455
514
 
456
- Controller actions are wrapped with `:atomic` strategy with middleware just to reduce amount of index update requests inside actions.
515
+ Migrations are wrapped with the `:bypass` strategy. Because the main behavior implies that indices are reset after migration, there is no need for extra index updates. Also indexing might be broken during migrations because of the outdated schema.
457
516
 
458
- It is also a good idea to set up `:bypass` strategy inside your test suite and import objects manually only when needed, plus use `Chewy.massacre` when needed to flush test ES indexes before every example. This will allow to minimize unnecessary ES requests and reduce overhead.
517
+ Controller actions are wrapped with the `:atomic` strategy with middleware just to reduce the number of index update requests inside actions.
459
518
 
519
+ It is also a good idea to set up the `:bypass` strategy inside your test suite and import objects manually only when needed, and use `Chewy.massacre` when needed to flush test ES indices before every example. This will allow you to minimize unnecessary ES requests and reduce overhead.
460
520
 
461
521
  ```ruby
462
522
  RSpec.configure do |config|
@@ -485,24 +545,20 @@ scope.only(:id, :email) # returns ids and emails only
485
545
  scope.merge(other_scope) # queries could be merged
486
546
  ```
487
547
 
488
- Also, queries can be performed on a type individually
548
+ Also, queries can be performed on a type individually:
489
549
 
490
550
  ```ruby
491
551
  UsersIndex::User.filter(term: {name: 'foo'}) # will return UserIndex::User collection only
492
552
  ```
493
553
 
494
- If you are performing more than one `filter` or `query` in the chain,
495
- all the filters and queries will be concatenated in the way specified by
554
+ If you are performing more than one `filter` or `query` in the chain, all the filters and queries will be concatenated in the way specified by
496
555
  `filter_mode` and `query_mode` respectively.
497
556
 
498
- Default `filter_mode` is `:and` and default `query_mode` is `bool`.
557
+ The default `filter_mode` is `:and` and the default `query_mode` is `bool`.
499
558
 
500
- Available filter modes are: `:and`, `:or`, `:must`, `:should` and
501
- any minimum_should_match-acceptable value
559
+ Available filter modes are: `:and`, `:or`, `:must`, `:should` and any minimum_should_match-acceptable value
502
560
 
503
- Available query modes are: `:must`, `:should`, `:dis_max`, any
504
- minimum_should_match-acceptable value or float value for dis_max
505
- query with tie_breaker specified.
561
+ Available query modes are: `:must`, `:should`, `:dis_max`, any minimum_should_match-acceptable value or float value for dis_max query with tie_breaker specified.
506
562
 
507
563
  ```ruby
508
564
  UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 } # will be wrapped with `and` filter
@@ -514,7 +570,7 @@ See [query.rb](lib/chewy/query.rb) for more details.
514
570
 
515
571
  ### Additional query action.
516
572
 
517
- You may also perform additional actions on query scope, such as deleting of all the scope documents:
573
+ You may also perform additional actions on the query scope, such as deleting of all the scope documents:
518
574
 
519
575
  ```ruby
520
576
  UsersIndex.delete_all
@@ -523,17 +579,16 @@ UsersIndex.filter{ age < 42 }.delete_all
523
579
  UsersIndex::User.filter{ age < 42 }.delete_all
524
580
  ```
525
581
 
526
- ### Filters query DSL.
582
+ ### Filters query DSL
527
583
 
528
- There is a test version of filters creating DSL:
584
+ There is a test version of the filter-creating DSL:
529
585
 
530
586
  ```ruby
531
587
  UsersIndex.filter{ name == 'Fred' } # will produce `term` filter.
532
588
  UsersIndex.filter{ age <= 42 } # will produce `range` filter.
533
589
  ```
534
590
 
535
- The basis of the DSL is expression.
536
- There are 2 types of expressions:
591
+ The basis of the DSL is the expression. There are 2 types of expressions:
537
592
 
538
593
  * Simple function
539
594
 
@@ -542,10 +597,8 @@ There are 2 types of expressions:
542
597
  UsersIndex.filter{ q(query_string: {query: 'lazy fox'}) } # query expression
543
598
  ```
544
599
 
545
- * Field-dependant composite expression.
546
- Consists of the field name (with dot notation or not),
547
- value and action operator between them. Field name might take
548
- additional options for passing to the result expression.
600
+ * Field-dependent composite expression
601
+ Consists of the field name (with or without dot notation), a value, and an action operator between them. The field name might take additional options for passing to the resulting expression.
549
602
 
550
603
  ```ruby
551
604
  UsersIndex.filter{ name == 'Name' } # simple field term filter
@@ -553,7 +606,7 @@ There are 2 types of expressions:
553
606
  UsersIndex.filter{ answers.title =~ /regexp/ } # regexp filter for `answers.title` field
554
607
  ```
555
608
 
556
- You can combine expressions as you wish with combination operators help
609
+ You can combine expressions as you wish with the help of combination operators.
557
610
 
558
611
  ```ruby
559
612
  UsersIndex.filter{ (name == 'Name') & (email == 'Email') } # combination produces `and` filter
@@ -564,10 +617,10 @@ UsersIndex.filter{
564
617
  } # many of the combination possibilities
565
618
  ```
566
619
 
567
- Also, there is a special syntax for cache enabling:
620
+ There is also a special syntax for cache enabling:
568
621
 
569
622
  ```ruby
570
- UsersIndex.filter{ ~name == 'Name' } # you can apply tilda to the field name
623
+ UsersIndex.filter{ ~name == 'Name' } # you can apply tilde to the field name
571
624
  UsersIndex.filter{ ~(name == 'Name') } # or to the whole expression
572
625
 
573
626
  # if you are applying cache to the one part of range filter
@@ -806,25 +859,102 @@ See [filters.rb](lib/chewy/query/filters.rb) for more details.
806
859
 
807
860
  ### Faceting
808
861
 
809
- Facets are an optional sidechannel you can request from elasticsearch describing certain fields of the resulting collection. The most common use for facets is to allow the user continue filtering specifically within the subset, as opposed to the global index.
862
+ Facets are an optional sidechannel you can request from Elasticsearch describing certain fields of the resulting collection. The most common use for facets is to allow the user to continue filtering specifically within the subset, as opposed to the global index.
810
863
 
811
- For instance, let's request the ```country``` field as a facet along with our users collection. We can do this with the #facets method like so:
864
+ For instance, let's request the `country` field as a facet along with our users collection. We can do this with the #facets method like so:
812
865
 
813
866
  ```ruby
814
867
  UsersIndex.filter{ [...] }.facets({countries: {terms: {field: 'country'}}})
815
868
  ```
816
869
 
817
- Let's look at what we asked from elasticsearch. The facets setter method accepts a hash. You can choose custom/semantic key names for this hash for your own convinience (in this case I used the plural version of the actual field), in our case: ```countries```. The following nested hash tells ES to grab and aggregate values (terms) from the ```country``` field on our indexed records.
870
+ Let's look at what we asked from Elasticsearch. The facets setter method accepts a hash. You can choose custom/semantic key names for this hash for your own convenience (in this case I used the plural version of the actual field), in our case `countries`. The following nested hash tells ES to grab and aggregate values (terms) from the `country` field on our indexed records.
818
871
 
819
- When the response comes back, it will have the ```:facets``` sidechannel included:
872
+ The response will include the `:facets` sidechannel:
820
873
 
821
874
  ```
822
875
  < { ... ,"facets":{"countries":{"_type":"terms","missing":?,"total":?,"other":?,"terms":[{"term":"USA","count":?},{"term":"Brazil","count":?}, ...}}
823
876
  ```
824
877
 
878
+ ### Aggregations
879
+
880
+ Aggregations are part of the optional sidechannel that can be requested with a query.
881
+
882
+ You interact with aggregations using the composable #aggregations method (or its alias #aggs)
883
+
884
+ Let's look at an example.
885
+
886
+ ```ruby
887
+ class UsersIndex < Chewy::Index
888
+ define_type User do
889
+ field :name
890
+ field :rating
891
+ end
892
+ end
893
+
894
+ all_johns = UsersIndex::User.filter { name == 'john' }.aggs({ avg_rating: { avg: { field: 'rating' } } })
895
+
896
+ avg_johns_rating = all_johns.aggs
897
+ # => {"avg_rating"=>{"value"=>3.5}}
898
+ ```
899
+
900
+ It is convenient to name aggregations that you intend to reuse regularly. This is achieve with the .aggregation method,
901
+ which is also available under the .agg alias method.
902
+
903
+ Here's the same example from before
904
+
905
+ ```ruby
906
+ class UsersIndex < Chewy::Index
907
+ define_type User do
908
+ field :name
909
+ field :rating, type: "long"
910
+ agg :avg_rating do
911
+ { avg: { field: 'rating' } }
912
+ end
913
+ end
914
+ end
915
+
916
+ all_johns = UsersIndex::User.filter { name == 'john' }.aggs(:avg_rating)
917
+
918
+ avg_johns_rating = all_johns.aggs
919
+ # => {"avg_rating"=>{"value"=>3.5}}
920
+ ```
921
+
922
+ It is possible to run into collisions between named aggregations. This occurs when there is more than one aggregation
923
+ with the same name. To explicitly reference an aggregation you provide a string to the #aggs method of the form:
924
+ `index_name#document_type.aggregation_name`
925
+
926
+ Consider this example where there are two separate aggregations named `avg_rating`
927
+
928
+ ```ruby
929
+ class UsersIndex < Chewy::Index
930
+ define_type User do
931
+ field :name
932
+ field :rating, type: "long"
933
+ agg :avg_rating do
934
+ { avg: { field: 'rating' } }
935
+ end
936
+ end
937
+ define_type Post do
938
+ field :title
939
+ field :body
940
+ field :comments do
941
+ field :message
942
+ field :rating, type: "long"
943
+ end
944
+ agg :avg_rating do
945
+ { avg: { field: 'comments.rating' } }
946
+ end
947
+ end
948
+ end
949
+
950
+ all_docs = UsersIndex.filter {match_all}.aggs("users#user.avg_rating")
951
+ all_docs.aggs
952
+ # => {"users#user.avg_rating"=>{"value"=>3.5}}
953
+ ```
954
+
825
955
  ### Script fields
826
956
 
827
- Script fields allow to execute elasticsearch's scripting language such as groovy, javascript and etc. More about supported languages and what is scripting [here](https://www.elastic.co/guide/en/elasticsearch/reference/0.90/modules-scripting.html). This feature allows to calculate distance between geo points, for example. This is how to use the DSL:
957
+ Script fields allow you to execute Elasticsearch's scripting languages such as groovy and javascript. More about supported languages and what scripting is [here](https://www.elastic.co/guide/en/elasticsearch/reference/0.90/modules-scripting.html). This feature allows you to calculate the distance between geo points, for example. This is how to use the DSL:
828
958
 
829
959
  ```ruby
830
960
  UsersIndex.script_fields(
@@ -837,7 +967,7 @@ UsersIndex.script_fields(
837
967
  }
838
968
  )
839
969
  ```
840
- `coordinates` here is a field with `geo_point` type. There will be `distance` field for the index's model in the search result.
970
+ Here, `coordinates` is a field with type `geo_point`. There will be a `distance` field for the index's model in the search result.
841
971
 
842
972
  ### Script scoring
843
973
 
@@ -849,7 +979,7 @@ UsersIndex.script_score("_score * doc['my_numeric_field'].value")
849
979
 
850
980
  ### Boost Factor
851
981
 
852
- Boost factors are a way to add a boost to a query where documents match the filter. If you have some users who are experts and some are regular users, you might want to give the experts a higher score and boost to the top of the search results. You can accomplish this by using the #boost_factor method and adding a boost score for an expert user of 5:
982
+ Boost factors are a way to add a boost to a query where documents match the filter. If you have some users who are experts and some who are regular users, you might want to give the experts a higher score and boost to the top of the search results. You can accomplish this by using the #boost_factor method and adding a boost score of 5 for an expert user:
853
983
 
854
984
  ```ruby
855
985
  UsersIndex.boost_factor(5, filter: {term: {type: 'Expert'}})
@@ -857,7 +987,7 @@ UsersIndex.boost_factor(5, filter: {term: {type: 'Expert'}})
857
987
 
858
988
  ### Objects loading
859
989
 
860
- It is possible to load source objects from database for every search result:
990
+ It is possible to load source objects from the database for every search result:
861
991
 
862
992
  ```ruby
863
993
  scope = UsersIndex.filter(range: {rating: {gte: 100}})
@@ -872,7 +1002,7 @@ scope.load(scope: ->{ includes(:country) }) # and more common scope applied to e
872
1002
  scope.only(:id).load # it is optimal to request ids only if you are not planning to use type objects
873
1003
  ```
874
1004
 
875
- The `preload` method takes the same options as `load` and ORM/ODM objects will be loaded, but scope will still return array of Chewy wrappers. To access real objects use `_object` wrapper method:
1005
+ The `preload` method takes the same options as `load` and ORM/ODM objects will be loaded, but the scope will still return an array of Chewy wrappers. To access real objects use the `_object` wrapper method:
876
1006
 
877
1007
  ```ruby
878
1008
  UsersIndex.filter(range: {rating: {gte: 100}}).preload(...).query(...).map(&:_object)
@@ -882,7 +1012,7 @@ See [loading.rb](lib/chewy/query/loading.rb) for more details.
882
1012
 
883
1013
  ### `ActiveSupport::Notifications` support
884
1014
 
885
- Chewy has notifing the following events:
1015
+ Chewy has notifying the following events:
886
1016
 
887
1017
  #### `search_query.chewy` payload
888
1018
 
@@ -892,7 +1022,7 @@ Chewy has notifing the following events:
892
1022
  #### `import_objects.chewy` payload
893
1023
 
894
1024
  * `payload[:type]`: currently imported type
895
- * `payload[:import]`: imports stast, total imported and deleted objects count:
1025
+ * `payload[:import]`: imports stats, total imported and deleted objects count:
896
1026
 
897
1027
  ```ruby
898
1028
  {index: 30, delete: 5}
@@ -941,25 +1071,24 @@ end
941
1071
 
942
1072
  ### Rake tasks
943
1073
 
944
- Inside Rails application some index mantaining rake tasks are defined.
1074
+ Inside the Rails application, some index-maintaining rake tasks are defined.
945
1075
 
946
1076
  ```bash
947
- rake chewy:reset # resets all the existing indexes, declared in app/chewy
1077
+ rake chewy:reset # resets all the existing indices, declared in app/chewy
948
1078
  rake chewy:reset[users] # resets UsersIndex only
949
1079
 
950
- rake chewy:update # updates all the existing indexes, declared in app/chewy
1080
+ rake chewy:update # updates all the existing indices, declared in app/chewy
951
1081
  rake chewy:update[users] # updates UsersIndex only
952
1082
  ```
953
1083
 
954
- Also `rake chewy:reset` performs zero-downtime reindexing as described here: https://www.elastic.co/blog/changing-mapping-with-zero-downtime. So basically rake task creates new index with uniq suffix and then simply aliases it to the common index name. Previous index is deleted afterwards (see `Chewy::Index.reset!` for more details).
1084
+ `rake chewy:reset` performs zero-downtime reindexing as described [here](https://www.elastic.co/blog/changing-mapping-with-zero-downtime). So basically rake task creates a new index with uniq suffix and then simply aliases it to the common index name. The previous index is deleted afterwards (see `Chewy::Index.reset!` for more details).
955
1085
 
956
1086
 
957
1087
  ### Rspec integration
958
1088
 
959
- Just add `require 'chewy/rspec'` to your spec_helper.rb and you will get additional features:
960
- See [update_index.rb](lib/chewy/rspec/update_index.rb) for more details.
1089
+ Just add `require 'chewy/rspec'` to your spec_helper.rb and you will get additional features: See [update_index.rb](lib/chewy/rspec/update_index.rb) for more details.
961
1090
 
962
- If you use `DatabaseCleaner` in your tests with `transaction` (strategy)[https://github.com/DatabaseCleaner/database_cleaner#how-to-use] you may run into the problem that `ActiveRecord`'s models are not indexed automatically on save them despite of the fact that you set the callbacks to do this with the `update_index` method. The issue arises because `chewy` indexes data on `after_commit` run as default but all `after_commit` callbacks are not run with the `DatabaseCleaner`'s' `transaction` strategy. You can solve the issue by changing the `Chewy.use_after_commit_callbacks` option. Just add the following initializer in your Rails application:
1091
+ If you use `DatabaseCleaner` in your tests with [the `transaction` strategy](https://github.com/DatabaseCleaner/database_cleaner#how-to-use), you may run into the problem that `ActiveRecord`'s models are not indexed automatically on save despite the fact that you set the callbacks to do this with the `update_index` method. The issue arises because `chewy` indexes data on `after_commit` run as default, but all `after_commit` callbacks are not run with the `DatabaseCleaner`'s' `transaction` strategy. You can solve this issue by changing the `Chewy.use_after_commit_callbacks` option. Just add the following initializer in your Rails application:
963
1092
 
964
1093
  ```ruby
965
1094
  #config/initializers/chewy.rb
@@ -969,20 +1098,20 @@ Chewy.use_after_commit_callbacks = !Rails.env.test?
969
1098
  ## TODO a.k.a coming soon:
970
1099
 
971
1100
  * Typecasting support
972
- * Advanced (simplyfied) query DSL: `UsersIndex.query { email == 'my@gmail.com' }` will produce term query
1101
+ * Advanced (simplified) query DSL: `UsersIndex.query { email == 'my@gmail.com' }` will produce term query
973
1102
  * update_all support
974
1103
  * Maybe, closer ORM/ODM integration, creating index classes implicitly
975
1104
 
976
1105
  ## Contributing
977
1106
 
978
- 1. Fork it ( http://github.com/toptal/chewy/fork )
1107
+ 1. Fork it (http://github.com/toptal/chewy/fork)
979
1108
  2. Create your feature branch (`git checkout -b my-new-feature`)
980
1109
  3. Implement your changes, cover it with specs and make sure old specs are passing
981
1110
  4. Commit your changes (`git commit -am 'Add some feature'`)
982
1111
  5. Push to the branch (`git push origin my-new-feature`)
983
1112
  6. Create new Pull Request
984
1113
 
985
- Use the following Rake tasks to control ElasticSearch cluster while developing.
1114
+ Use the following Rake tasks to control the Elasticsearch cluster while developing.
986
1115
 
987
1116
  ```bash
988
1117
  rake elasticsearch:start # start Elasticsearch cluster on 9250 port for tests