algoliasearch-rails 1.14.1 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,35 +1,43 @@
1
+ <!--NO_HTML-->
2
+
1
3
  Algolia Search for Rails
2
4
  ==================
3
5
 
4
- This gem let you easily integrate the Algolia Search API to your favorite ORM. It's based on the [algoliasearch-client-ruby](https://github.com/algolia/algoliasearch-client-ruby) gem. Both Rails 3.x and Rails 4.x are supported.
6
+ <!--/NO_HTML-->
7
+
8
+ This gem let you easily integrate the Algolia Search API to your favorite ORM. It's based on the [algoliasearch-client-ruby](https://github.com/algolia/algoliasearch-client-ruby) gem. Rails 3.x, 4.x and 5.x are all supported.
5
9
 
6
- You might be interested in the sample Ruby on Rails application providing a ```typeahead.js```-based auto-completion and ```Google```-like instant search: [algoliasearch-rails-example](https://github.com/algolia/algoliasearch-rails-example/).
10
+ You might be interested in the sample Ruby on Rails application providing a ```autocomplete.js```-based auto-completion and ```instantsearch.js```-based instant search results page: [algoliasearch-rails-example](https://github.com/algolia/algoliasearch-rails-example/).
7
11
 
8
- [![Build Status](https://travis-ci.org/algolia/algoliasearch-rails.png?branch=master)](https://travis-ci.org/algolia/algoliasearch-rails) [![Gem Version](https://badge.fury.io/rb/algoliasearch-rails.png)](http://badge.fury.io/rb/algoliasearch-rails) [![Code Climate](https://codeclimate.com/github/algolia/algoliasearch-rails.png)](https://codeclimate.com/github/algolia/algoliasearch-rails) ![ActiveRecord](https://img.shields.io/badge/ActiveRecord-yes-blue.svg?style=flat-square) ![Mongoid](https://img.shields.io/badge/Mongoid-yes-blue.svg?style=flat-square) ![Sequel](https://img.shields.io/badge/Sequel-yes-blue.svg?style=flat-square)
12
+ [![Build Status](https://travis-ci.org/algolia/algoliasearch-rails.svg?branch=master)](https://travis-ci.org/algolia/algoliasearch-rails) [![Gem Version](https://badge.fury.io/rb/algoliasearch-rails.svg)](http://badge.fury.io/rb/algoliasearch-rails) [![Code Climate](https://codeclimate.com/github/algolia/algoliasearch-rails.svg)](https://codeclimate.com/github/algolia/algoliasearch-rails) ![ActiveRecord](https://img.shields.io/badge/ActiveRecord-yes-blue.svg?style=flat-square) ![Mongoid](https://img.shields.io/badge/Mongoid-yes-blue.svg?style=flat-square) ![Sequel](https://img.shields.io/badge/Sequel-yes-blue.svg?style=flat-square)
13
+
14
+ <!--NO_HTML-->
9
15
 
10
16
  Table of Content
11
- -------------
12
- **Get started**
17
+ =============
13
18
 
14
19
  1. [Install](#install)
15
20
  1. [Setup](#setup)
16
21
  1. [Quick Start](#quick-start)
17
- 1. [Ranking & Relevance](#ranking--relevance)
18
22
  1. [Options](#options)
19
23
  1. [Configuration example](#configuration-example)
20
24
  1. [Indexing](#indexing)
21
25
  1. [Master/Slave](#masterslave)
26
+ 1. [Share a single index](#share-a-single-index)
22
27
  1. [Target multiple indexes](#target-multiple-indexes)
23
28
  1. [Tags](#tags)
24
29
  1. [Search](#search)
25
30
  1. [Faceting](#faceting)
31
+ 1. [Group by](#group-by)
26
32
  1. [Geo-search](#geo-search)
27
- 1. [Typeahead UI](#typeahead-ui)
28
33
  1. [Caveats](#caveats)
29
34
  1. [Note on testing](#note-on-testing)
30
35
 
31
- Install
32
- -------------
36
+ <!--/NO_HTML-->
37
+
38
+ ## Setup
39
+
40
+ ### Install
33
41
 
34
42
  ```sh
35
43
  gem install algoliasearch-rails
@@ -47,8 +55,8 @@ And run:
47
55
  bundle install
48
56
  ```
49
57
 
50
- Setup
51
- -------------
58
+ ### Configuration
59
+
52
60
  Create a new file <code>config/initializers/algoliasearch.rb</code> to setup your <code>APPLICATION_ID</code> and <code>API_KEY</code>.
53
61
 
54
62
 
@@ -58,14 +66,9 @@ AlgoliaSearch.configuration = { application_id: 'YourApplicationID', api_key: 'Y
58
66
 
59
67
  The gem is compatible with [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord), [Mongoid](https://github.com/mongoid/mongoid) and [Sequel](https://github.com/jeremyevans/sequel).
60
68
 
61
- We support both [will_paginate](https://github.com/mislav/will_paginate) and [kaminari](https://github.com/amatsuda/kaminari) as pagination backend. For example to use <code>:will_paginate</code>, specify the <code>:pagination_backend</code> as follow:
62
-
63
- ```ruby
64
- AlgoliaSearch.configuration = { application_id: 'YourApplicationID', api_key: 'YourAPIKey', pagination_backend: :will_paginate }
65
- ```
69
+ ## Quick Start
66
70
 
67
- Quick Start
68
- -------------
71
+ ### Schema
69
72
 
70
73
  The following code will create a <code>Contact</code> index and add search capabilities to your <code>Contact</code> model:
71
74
 
@@ -108,7 +111,7 @@ class Product < ActiveRecord::Base
108
111
  end
109
112
  ```
110
113
 
111
- #### Ranking & Relevance
114
+ ### Relevancy
112
115
 
113
116
  We provide many ways to configure your index allowing you to tune your overall index relevancy. The most important ones are the **searchable attributes** and the attributes reflecting **record popularity**.
114
117
 
@@ -134,7 +137,25 @@ class Product < ActiveRecord::Base
134
137
  end
135
138
  ```
136
139
 
137
- #### Frontend Search (realtime experience)
140
+ ### Indexing
141
+
142
+ To index a model, simple call `reindex` on the class:
143
+
144
+ ```ruby
145
+ Product.reindex
146
+ ```
147
+
148
+ To index all of your models, you can do something like this:
149
+
150
+ ```ruby
151
+ Rails.application.eager_load! # Ensure all models are loaded (required in development).
152
+
153
+ algolia_models = ActiveRecord::Base.descendants.select{ |model| model.respond_to?(:reindex) }
154
+
155
+ algolia_models.each(&:reindex)
156
+ ```
157
+
158
+ ### Frontend Search (realtime experience)
138
159
 
139
160
  Traditional search implementations tend to have search logic and functionality on the backend. This made sense when the search experience consisted of a user entering a search query, executing that search, and then being redirected to a search result page.
140
161
 
@@ -151,14 +172,18 @@ Then in your JavaScript code you can do:
151
172
  ```js
152
173
  var client = algoliasearch(ApplicationID, Search-Only-API-Key);
153
174
  var index = client.initIndex('YourIndexName');
154
- index.search('something', function(success, hits) {
155
- console.log(success, hits)
156
- }, { hitsPerPage: 10, page: 0 });
175
+ index.search('something', { hitsPerPage: 10, page: 0 })
176
+ .then(function searchDone(content) {
177
+ console.log(content)
178
+ })
179
+ .catch(function searchFailure(err) {
180
+ console.error(err);
181
+ });
157
182
  ```
158
183
 
159
184
  **We recently (March 2015) released a new version (V3) of our JavaScript client, if you were using our previous version (V2), [read the migration guide](https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x)**
160
185
 
161
- #### Backend Search
186
+ ### Backend Search
162
187
 
163
188
  If you want to search from your backend you can use the `raw_search` method. It retrieves the raw JSON answer from the API:
164
189
 
@@ -172,7 +197,31 @@ You could also use `search` but it's not recommended. This method will fetch the
172
197
  p Contact.search("jon doe") # we recommend to use `raw_search` to avoid the database lookup
173
198
  ```
174
199
 
175
- #### Notes
200
+ ### Backend Pagination
201
+
202
+ Even if we **highly recommend to perform all search (and therefore pagination) operations from your frontend using JavaScript**, we support both [will_paginate](https://github.com/mislav/will_paginate) and [kaminari](https://github.com/amatsuda/kaminari) as pagination backend.
203
+
204
+ To use <code>:will_paginate</code>, specify the <code>:pagination_backend</code> as follow:
205
+
206
+ ```ruby
207
+ AlgoliaSearch.configuration = { application_id: 'YourApplicationID', api_key: 'YourAPIKey', pagination_backend: :will_paginate }
208
+ ```
209
+
210
+ Then, as soon as you use the `search` method, the returning results will be a paginated set:
211
+
212
+ ```ruby
213
+ # in your controller
214
+ @results = MyModel.search('foo', hitsPerPage: 10)
215
+
216
+ # in your views
217
+ # if using will_paginate
218
+ <%= will_paginate @results %>
219
+
220
+ # if using kaminari
221
+ <%= paginate @results %>
222
+ ```
223
+
224
+ ### Notes
176
225
 
177
226
  All methods injected by the ```AlgoliaSearch``` include are prefixed by ```algolia_``` and aliased to the associated short names if they aren't already defined.
178
227
 
@@ -182,10 +231,9 @@ Contact.algolia_reindex! # <=> Contact.reindex!
182
231
  Contact.algolia_search("jon doe") # <=> Contact.search("jon doe")
183
232
  ```
184
233
 
185
- Options
186
- ----------
234
+ ## Options
187
235
 
188
- #### Auto-indexing & asynchronism
236
+ ### Auto-indexing & asynchronism
189
237
 
190
238
  Each time a record is saved; it will be - asynchronously - indexed. On the other hand, each time a record is destroyed, it will be - asynchronously - removed from the index. That means that a network call with the ADD/DELETE operation is sent **synchronously** to the Algolia API but then the engine will **asynchronously** process the operation (so if you do a search just after, the results may not reflect it yet).
191
239
 
@@ -201,7 +249,7 @@ class Contact < ActiveRecord::Base
201
249
  end
202
250
  ```
203
251
 
204
- ##### Temporary disable auto-indexing
252
+ #### Temporary disable auto-indexing
205
253
 
206
254
  You can temporary disable auto-indexing using the <code>without_auto_index</code> scope. This is often used for performance reason.
207
255
 
@@ -213,7 +261,7 @@ end
213
261
  Contact.reindex! # will use batch operations
214
262
  ```
215
263
 
216
- ##### Queues & background jobs
264
+ #### Queues & background jobs
217
265
 
218
266
  You can configure the auto-indexing & auto-removal process to use a queue to perform those operations in background. ActiveJob (Rails >=4.2) queues are used by default but you can define your own queuing mechanism:
219
267
 
@@ -227,7 +275,31 @@ class Contact < ActiveRecord::Base
227
275
  end
228
276
  ```
229
277
 
230
- ##### With Sidekiq
278
+ #### Things to Consider
279
+
280
+ If you are performing updates & deletions in the background then a record deletion can be committed to your database prior
281
+ to the job actually executing. Thus if you were to load the record to remove it from the database than your ActiveRecord#find will fail with a RecordNotFound.
282
+
283
+ In this case you can bypass loading the record from ActiveRecord and just communicate with the index directly:
284
+
285
+ ```ruby
286
+ class MySidekiqWorker
287
+ def perform(id, remove)
288
+ if remove
289
+ # the record has likely already been removed from your database so we cannot
290
+ # use ActiveRecord#find to load it
291
+ index = Algolia::Index.new("index_name")
292
+ index.delete_object(id)
293
+ else
294
+ # the record should be present
295
+ c = Contact.find(id)
296
+ c.index!
297
+ end
298
+ end
299
+ end
300
+ ```
301
+
302
+ #### With Sidekiq
231
303
 
232
304
  If you're using [Sidekiq](https://github.com/mperham/sidekiq):
233
305
 
@@ -252,7 +324,7 @@ class MySidekiqWorker
252
324
  end
253
325
  ```
254
326
 
255
- ##### With DelayedJob
327
+ #### With DelayedJob
256
328
 
257
329
  If you're using [delayed_job](https://github.com/collectiveidea/delayed_job):
258
330
 
@@ -275,7 +347,7 @@ end
275
347
 
276
348
  ```
277
349
 
278
- ##### Synchronism & testing
350
+ #### Synchronism & testing
279
351
 
280
352
  You can force indexing and removing to be synchronous (in that case the gem will call the `wait_task` method to ensure the operation has been taken into account once the method returns) by setting the following option: (this is **NOT** recommended, except for testing purpose)
281
353
 
@@ -289,7 +361,7 @@ class Contact < ActiveRecord::Base
289
361
  end
290
362
  ```
291
363
 
292
- #### Exceptions
364
+ ### Exceptions
293
365
 
294
366
  You can disable exceptions that could be raised while trying to reach Algolia's API by using the `raise_on_failure` option:
295
367
 
@@ -304,7 +376,7 @@ class Contact < ActiveRecord::Base
304
376
  end
305
377
  ```
306
378
 
307
- #### Custom index name
379
+ ### Custom index name
308
380
 
309
381
  By default, the index name will be the class name, e.g. "Contact". You can customize the index name by using the `index_name` option:
310
382
 
@@ -318,7 +390,7 @@ class Contact < ActiveRecord::Base
318
390
  end
319
391
  ```
320
392
 
321
- #### Per-environment indexes
393
+ ### Per-environment indexes
322
394
 
323
395
  You can suffix the index name with the current Rails environment using the following option:
324
396
 
@@ -332,7 +404,7 @@ class Contact < ActiveRecord::Base
332
404
  end
333
405
  ```
334
406
 
335
- #### Custom attribute definition
407
+ ### Custom attribute definition
336
408
 
337
409
  You can use a block to specify a complex attribute value
338
410
 
@@ -373,7 +445,7 @@ class Contact < ActiveRecord::Base
373
445
  end
374
446
  ```
375
447
 
376
- #### Nested objects/relations
448
+ ### Nested objects/relations
377
449
 
378
450
  You can easily embed nested objects defining an extra attribute returning any JSON-compliant object (an array or a hash or a combination of both).
379
451
 
@@ -400,7 +472,7 @@ class Profile < ActiveRecord::Base
400
472
  end
401
473
  ```
402
474
 
403
- #### Custom ```objectID```
475
+ ### Custom ```objectID```
404
476
 
405
477
  By default, the `objectID` is based on your record's `id`. You can change this behavior specifying the `:id` option (be sure to use a uniq field).
406
478
 
@@ -413,10 +485,12 @@ class UniqUser < ActiveRecord::Base
413
485
  end
414
486
  ```
415
487
 
416
- #### Restrict indexing to a subset of your data
488
+ ### Restrict indexing to a subset of your data
417
489
 
418
490
  You can add constraints controlling if a record must be indexed by using options the ```:if``` or ```:unless``` options.
419
491
 
492
+ It allows you to do conditional indexing on a per document basis.
493
+
420
494
  ```ruby
421
495
  class Post < ActiveRecord::Base
422
496
  include AlgoliaSearch
@@ -467,7 +541,7 @@ or
467
541
  MyModel.index_objects MyModel.limit(5)
468
542
  ```
469
543
 
470
- #### Sanitizer
544
+ ### Sanitizer
471
545
 
472
546
  You can sanitize all your attributes using the ```sanitize``` option. It will strip all HTML tags from your attributes.
473
547
 
@@ -489,7 +563,7 @@ gem 'rails-html-sanitizer'
489
563
  ```
490
564
 
491
565
 
492
- #### UTF-8 Encoding
566
+ ### UTF-8 Encoding
493
567
 
494
568
  You can force the UTF-8 encoding of all your attributes using the ```force_utf8_encoding``` option:
495
569
 
@@ -507,8 +581,7 @@ end
507
581
  ***Notes:*** This option is not compatible with Ruby 1.8
508
582
 
509
583
 
510
- Configuration example
511
- ---------------------
584
+ ### Configuration example
512
585
 
513
586
  Here is a real-word configuration example (from [HN Search](https://github.com/algolia/hn-search)):
514
587
 
@@ -565,10 +638,9 @@ class Item < ActiveRecord::Base
565
638
  end
566
639
  ```
567
640
 
568
- Indexing
569
- ---------
641
+ ## Indexing
570
642
 
571
- #### Manual indexing
643
+ ### Manual indexing
572
644
 
573
645
  You can trigger indexing using the <code>index!</code> instance method.
574
646
 
@@ -577,7 +649,7 @@ c = Contact.create!(params[:contact])
577
649
  c.index!
578
650
  ```
579
651
 
580
- #### Manual removal
652
+ ### Manual removal
581
653
 
582
654
  And trigger index removing using the <code>remove_from_index!</code> instance method.
583
655
 
@@ -586,21 +658,29 @@ c.remove_from_index!
586
658
  c.destroy
587
659
  ```
588
660
 
589
- #### Reindexing
661
+ ### Reindexing
662
+
663
+ The gem provides 2 ways to reindex all your objects:
664
+
665
+ #### Atomical reindexing
590
666
 
591
- To *safely* reindex all your records (index to a temporary index + move the temporary index to the current one atomically), use the <code>reindex</code> class method:
667
+ To reindex all your records (taking into account the deleted objects), the `reindex` class method indexes all your objects to a temporary index called `<INDEX_NAME>.tmp` and moves the temporary index to the final one once everything is indexed (atomically). This is the safest way to reindex all your content.
592
668
 
593
669
  ```ruby
594
670
  Contact.reindex
595
671
  ```
596
672
 
597
- To reindex all your records (in place, without deleting out-dated records), use the <code>reindex!</code> class method:
673
+ **Notes**: if you're using an index-specific API key, ensure you're allowing both `<INDEX_NAME>` and `<INDEX_NAME>.tmp`.
674
+
675
+ #### Regular reindexing
676
+
677
+ To reindex all your objects in place (without temporary index and therefore without deleting removed objects), use the `reindex!` class method:
598
678
 
599
679
  ```ruby
600
680
  Contact.reindex!
601
681
  ```
602
682
 
603
- #### Clearing an index
683
+ ### Clearing an index
604
684
 
605
685
  To clear an index, use the <code>clear_index!</code> class method:
606
686
 
@@ -608,7 +688,7 @@ To clear an index, use the <code>clear_index!</code> class method:
608
688
  Contact.clear_index!
609
689
  ```
610
690
 
611
- #### Using the underlying index
691
+ ### Using the underlying index
612
692
 
613
693
  You can access the underlying `index` object by calling the `index` class method:
614
694
 
@@ -617,8 +697,9 @@ index = Contact.index
617
697
  # index.get_settings, index.partial_update_object, ...
618
698
  ```
619
699
 
620
- Master/slave
621
- ---------
700
+ ## Indexes
701
+
702
+ ### Master/slave
622
703
 
623
704
  You can define slave indexes using the <code>add_slave</code> method:
624
705
 
@@ -653,8 +734,45 @@ Book.raw_search 'foo bar', slave: 'Book_by_editor'
653
734
  Book.search 'foo bar', slave: 'Book_by_editor'
654
735
  ```
655
736
 
656
- Target multiple indexes
657
- ---------
737
+ ### Share a single index
738
+
739
+ It can make sense to share an index between several models. In order to implement that, you'll need to ensure you don't have any conflict with the `objectID` of the underlying models.
740
+
741
+ ```ruby
742
+ class Student < ActiveRecord::Base
743
+ attr_protected
744
+
745
+ include AlgoliaSearch
746
+
747
+ algoliasearch index_name: 'people', id: :algolia_id do
748
+ # [...]
749
+ end
750
+
751
+ private
752
+ def algolia_id
753
+ "student_#{id}" # ensure the teacher & student IDs are not conflicting
754
+ end
755
+ end
756
+
757
+ class Teacher < ActiveRecord::Base
758
+ attr_protected
759
+
760
+ include AlgoliaSearch
761
+
762
+ algoliasearch index_name: 'people', id: :algolia_id do
763
+ # [...]
764
+ end
765
+
766
+ private
767
+ def algolia_id
768
+ "teacher_#{id}" # ensure the teacher & student IDs are not conflicting
769
+ end
770
+ end
771
+ ```
772
+
773
+ ***Notes:*** If you target a single index from several models, you must never use `MyModel.reindex` and only use `MyModel.reindex!`. The `reindex` method uses a temporary index to perform an atomic reindexing: if you use it, the resulting index will only contain records for the current model because it will not reindex the others.
774
+
775
+ ### Target multiple indexes
658
776
 
659
777
  You can index a record in several indexes using the <code>add_index</code> method:
660
778
 
@@ -667,7 +785,7 @@ class Book < ActiveRecord::Base
667
785
  PUBLIC_INDEX_NAME = "Book_#{Rails.env}"
668
786
  SECURED_INDEX_NAME = "SecuredBook_#{Rails.env}"
669
787
 
670
- # store all books in index 'SECURED_INDEX_NAME'
788
+ # store all books in index 'SECURED_INDEX_NAME'
671
789
  algoliasearch index_name: SECURED_INDEX_NAME do
672
790
  attributesToIndex [:name, :author]
673
791
  # convert security to tags
@@ -697,8 +815,9 @@ Book.raw_search 'foo bar', index: 'Book_by_editor'
697
815
  Book.search 'foo bar', index: 'Book_by_editor'
698
816
  ```
699
817
 
700
- Tags
701
- -----
818
+ ## Features
819
+
820
+ ### Tags
702
821
 
703
822
  Use the <code>tags</code> method to add tags to your record:
704
823
 
@@ -728,8 +847,7 @@ end
728
847
 
729
848
  At query time, specify <code>{ tagFilters: 'tagvalue' }</code> or <code>{ tagFilters: ['tagvalue1', 'tagvalue2'] }</code> as search parameters to restrict the result set to specific tags.
730
849
 
731
- Search
732
- ----------
850
+ ### Search
733
851
 
734
852
  ***Notes:*** We recommend the usage of our [JavaScript API Client](https://github.com/algolia/algoliasearch-client-js) to perform queries directly from the end-user browser without going through your server.
735
853
 
@@ -765,7 +883,7 @@ class Contact < ActiveRecord::Base
765
883
 
766
884
  algoliasearch do
767
885
  attribute :first_name, :last_name, :email
768
-
886
+
769
887
  # default search parameters stored in the index settings
770
888
  minWordSizeForApprox1 4
771
889
  minWordSizeForApprox2 8
@@ -779,8 +897,7 @@ end
779
897
  p Contact.raw_search("jon doe", { :hitsPerPage => 5, :page => 2 })
780
898
  ```
781
899
 
782
- Faceting
783
- ---------
900
+ ### Faceting
784
901
 
785
902
  Facets can be retrieved calling the extra ```facets``` method of the search answer.
786
903
 
@@ -810,68 +927,46 @@ raw_json = Contact.raw_search("jon doe", { :facets => '*' })
810
927
  p raw_json['facets']
811
928
  ```
812
929
 
813
- Geo-Search
814
- -----------
930
+ ### Group by
815
931
 
816
- Use the <code>geoloc</code> method to localize your record:
932
+ More info on distinct for grouping can be found
933
+ [here](https://www.algolia.com/doc/guides/search/distinct#distinct-for-grouping).
817
934
 
818
935
  ```ruby
819
936
  class Contact < ActiveRecord::Base
820
937
  include AlgoliaSearch
821
938
 
822
939
  algoliasearch do
823
- geoloc :lat_attr, :lng_attr
940
+ # [...]
941
+
942
+ # specify the attribute to be used for distinguishing the records
943
+ # in this case the records will be grouped by company
944
+ attributeForDistinct "company"
824
945
  end
825
946
  end
826
947
  ```
827
948
 
828
- At query time, specify <code>{ aroundLatLng: "37.33, -121.89", aroundRadius: 50000 }</code> as search parameters to restrict the result set to 50KM around San Jose.
949
+ ### Geo-Search
829
950
 
830
- Typeahead UI
831
- -------------
832
-
833
- Require ```algolia/v3/algoliasearch.min``` (see [algoliasearch-client-js](https://github.com/algolia/algoliasearch-client-js)) and ```algolia/typeahead.jquery.js``` somewhere in your JavaScript manifest, for example in ```application.js``` if you are using Rails 3.1+:
834
-
835
- ```javascript
836
- //= require algolia/v3/algoliasearch.min
837
- //= require algolia/typeahead.jquery
838
- ```
951
+ Use the <code>geoloc</code> method to localize your record:
839
952
 
840
- We recommend the usage of [hogan](http://twitter.github.io/hogan.js/), a JavaScript templating engine from Twitter.
953
+ ```ruby
954
+ class Contact < ActiveRecord::Base
955
+ include AlgoliaSearch
841
956
 
842
- ```javascript
843
- //= require hogan
957
+ algoliasearch do
958
+ geoloc :lat_attr, :lng_attr
959
+ end
960
+ end
844
961
  ```
845
962
 
846
- Turns any ```input[type="text"]``` element into a typeahead, for example:
847
-
848
- ```javascript
849
- <input name="email" placeholder="test@example.org" id="user_email" />
850
-
851
- <script type="text/javascript">
852
- $(document).ready(function() {
853
- var client = algoliasearch('YourApplicationID', 'SearchOnlyApplicationKey');
854
- var template = Hogan.compile('{{{_highlightResult.email.value}}} ({{{_highlightResult.first_name.value}}} {{{_highlightResult.last_name.value}}})');
855
- $('input#user_email').typeahead(null, {
856
- source: client.initIndex('<%= Contact.index_name %>').ttAdapter(),
857
- displayKey: 'email',
858
- templates: {
859
- suggestion: function(hit) {
860
- return template.render(hit);
861
- }
862
- }
863
- });
864
- });
865
- </script>
866
- ```
963
+ At query time, specify <code>{ aroundLatLng: "37.33, -121.89", aroundRadius: 50000 }</code> as search parameters to restrict the result set to 50KM around San Jose.
867
964
 
868
- Caveats
869
- --------
965
+ ### Caveats
870
966
 
871
967
  This gem makes intensive use of Rails' callbacks to trigger the indexing tasks. If you're using methods bypassing ```after_validation```, ```before_save``` or ```after_commit``` callbacks, it will not index your changes. For example: ```update_attribute``` doesn't perform validations checks, to perform validations when updating use ```update_attributes```.
872
968
 
873
- Timeouts
874
- ---------
969
+ ### Timeouts
875
970
 
876
971
  You can configure a bunch of timeout threshold by setting the following options at initialization time:
877
972
 
@@ -887,8 +982,7 @@ AlgoliaSearch.configuration = {
887
982
  }
888
983
  ```
889
984
 
890
- Note on testing
891
- -----------------
985
+ ### Note on testing
892
986
 
893
987
  To run the specs, please set the <code>ALGOLIA_APPLICATION_ID</code> and <code>ALGOLIA_API_KEY</code> environment variables. Since the tests are creating and removing indexes, DO NOT use your production account.
894
988