algoliasearch-rails 1.20.4 → 2.2.2
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 +5 -5
- data/{ChangeLog → CHANGELOG.MD} +175 -1
- data/Gemfile +14 -37
- data/Gemfile.lock +189 -164
- data/LICENSE +6 -7
- data/README.md +118 -45
- data/algoliasearch-rails.gemspec +7 -7
- data/lib/algoliasearch/configuration.rb +28 -2
- data/lib/algoliasearch/pagination/kaminari.rb +1 -1
- data/lib/algoliasearch/tasks/algoliasearch.rake +6 -1
- data/lib/algoliasearch/utilities.rb +18 -1
- data/lib/algoliasearch/version.rb +1 -1
- data/lib/algoliasearch-rails.rb +216 -116
- data/spec/spec_helper.rb +20 -4
- metadata +11 -33
- data/.travis.yml +0 -55
data/LICENSE
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
1
|
+
MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2013 Algolia
|
4
|
-
http://www.algolia.com/
|
3
|
+
Copyright (c) 2013-Present Algolia
|
5
4
|
|
6
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
6
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -10,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
9
|
copies of the Software, and to permit persons to whom the Software is
|
11
10
|
furnished to do so, subject to the following conditions:
|
12
11
|
|
13
|
-
The above copyright notice and this permission notice shall be included in
|
14
|
-
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
15
14
|
|
16
15
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
16
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
17
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1,36 +1,50 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
<p align="center">
|
2
|
+
<a href="https://www.algolia.com">
|
3
|
+
<img alt="Algolia for Rails" src="https://raw.githubusercontent.com/algolia/algoliasearch-client-common/master/banners/rails.png"/>
|
4
|
+
</a>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<h4 align="center">The perfect starting point to integrate <a href="https://algolia.com" target="_blank">Algolia</a> within your Rails project</h4>
|
8
|
+
|
9
|
+
<p align="center">
|
10
|
+
<a href="https://circleci.com/gh/algolia/algoliasearch-rails"><img src="https://circleci.com/gh/algolia/algoliasearch-rails.svg?style=shield" alt="CircleCI" /></a>
|
11
|
+
<a href="http://badge.fury.io/rb/algoliasearch-rails"><img src="https://badge.fury.io/rb/algoliasearch-rails.svg" alt="Gem Version"/></a>
|
12
|
+
<a href="https://codeclimate.com/github/algolia/algoliasearch-rails"><img src="https://codeclimate.com/github/algolia/algoliasearch-rails.svg" alt="Code Climate"/></a>
|
13
|
+
<img src="https://img.shields.io/badge/ActiveRecord-yes-blue.svg?style=flat-square" alt="ActiveRecord"/>
|
14
|
+
<img src="https://img.shields.io/badge/Mongoid-yes-blue.svg?style=flat-square" alt="Mongoid"/>
|
15
|
+
<img src="https://img.shields.io/badge/Sequel-yes-blue.svg?style=flat-square" alt="Sequel"/>
|
16
|
+
</p>
|
17
|
+
|
18
|
+
<p align="center">
|
19
|
+
<a href="https://www.algolia.com/doc/framework-integration/rails/getting-started/setup/?language=ruby" target="_blank">Documentation</a> •
|
20
|
+
<a href="https://discourse.algolia.com" target="_blank">Community Forum</a> •
|
21
|
+
<a href="http://stackoverflow.com/questions/tagged/algolia" target="_blank">Stack Overflow</a> •
|
22
|
+
<a href="https://github.com/algolia/algoliasearch-rails/issues" target="_blank">Report a bug</a> •
|
23
|
+
<a href="https://www.algolia.com/doc/framework-integration/rails/troubleshooting/faq/" target="_blank">FAQ</a> •
|
24
|
+
<a href="https://www.algolia.com/support" target="_blank">Support</a>
|
25
|
+
</p>
|
6
26
|
|
7
27
|
|
8
28
|
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.
|
9
|
-
Rails
|
10
|
-
|
11
|
-
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/).
|
29
|
+
Rails 5.x and 6.x are supported.
|
12
30
|
|
31
|
+
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/).
|
13
32
|
|
14
33
|
|
15
34
|
|
16
35
|
## API Documentation
|
17
36
|
|
18
|
-
You can find the full reference on [Algolia's website](https://www.algolia.com/doc/
|
19
|
-
|
20
|
-
|
21
|
-
## Table of Contents
|
37
|
+
You can find the full reference on [Algolia's website](https://www.algolia.com/doc/framework-integration/rails/).
|
22
38
|
|
23
39
|
|
24
40
|
|
25
41
|
1. **[Setup](#setup)**
|
26
|
-
|
27
42
|
* [Install](#install)
|
28
43
|
* [Configuration](#configuration)
|
29
44
|
* [Timeouts](#timeouts)
|
30
45
|
* [Notes](#notes)
|
31
46
|
|
32
47
|
1. **[Usage](#usage)**
|
33
|
-
|
34
48
|
* [Index Schema](#index-schema)
|
35
49
|
* [Relevancy](#relevancy)
|
36
50
|
* [Indexing](#indexing)
|
@@ -44,13 +58,12 @@ You can find the full reference on [Algolia's website](https://www.algolia.com/d
|
|
44
58
|
* [Geo-Search](#geo-search)
|
45
59
|
|
46
60
|
1. **[Options](#options)**
|
47
|
-
|
48
61
|
* [Auto-indexing & asynchronism](#auto-indexing--asynchronism)
|
49
62
|
* [Custom index name](#custom-index-name)
|
50
63
|
* [Per-environment indices](#per-environment-indices)
|
51
64
|
* [Custom attribute definition](#custom-attribute-definition)
|
52
65
|
* [Nested objects/relations](#nested-objectsrelations)
|
53
|
-
* [Custom
|
66
|
+
* [Custom <code>objectID</code>](#custom-objectid)
|
54
67
|
* [Restrict indexing to a subset of your data](#restrict-indexing-to-a-subset-of-your-data)
|
55
68
|
* [Sanitizer](#sanitizer)
|
56
69
|
* [UTF-8 Encoding](#utf-8-encoding)
|
@@ -58,7 +71,6 @@ You can find the full reference on [Algolia's website](https://www.algolia.com/d
|
|
58
71
|
* [Configuration example](#configuration-example)
|
59
72
|
|
60
73
|
1. **[Indices](#indices)**
|
61
|
-
|
62
74
|
* [Manual indexing](#manual-indexing)
|
63
75
|
* [Manual removal](#manual-removal)
|
64
76
|
* [Reindexing](#reindexing)
|
@@ -69,12 +81,10 @@ You can find the full reference on [Algolia's website](https://www.algolia.com/d
|
|
69
81
|
* [Target multiple indices](#target-multiple-indices)
|
70
82
|
|
71
83
|
1. **[Testing](#testing)**
|
72
|
-
|
73
84
|
* [Notes](#notes)
|
74
85
|
|
75
|
-
|
76
|
-
|
77
|
-
|
86
|
+
1. **[Troubleshooting](#troubleshooting)**
|
87
|
+
* [Frequently asked questions](#frequently-asked-questions)
|
78
88
|
|
79
89
|
|
80
90
|
|
@@ -153,7 +163,7 @@ class Contact < ActiveRecord::Base
|
|
153
163
|
include AlgoliaSearch
|
154
164
|
|
155
165
|
algoliasearch do
|
156
|
-
|
166
|
+
attributes :first_name, :last_name, :email
|
157
167
|
end
|
158
168
|
end
|
159
169
|
```
|
@@ -414,7 +424,7 @@ Product.search_for_facet_values('category', 'phone', {
|
|
414
424
|
## Group by
|
415
425
|
|
416
426
|
More info on distinct for grouping can be found
|
417
|
-
[here](https://www.algolia.com/doc/guides/
|
427
|
+
[here](https://www.algolia.com/doc/guides/managing-results/refine-results/grouping/).
|
418
428
|
|
419
429
|
```ruby
|
420
430
|
class Contact < ActiveRecord::Base
|
@@ -454,7 +464,7 @@ At query time, specify <code>{ aroundLatLng: "37.33, -121.89", aroundRadius: 500
|
|
454
464
|
|
455
465
|
## Auto-indexing & asynchronism
|
456
466
|
|
457
|
-
Each time a record is saved
|
467
|
+
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).
|
458
468
|
|
459
469
|
You can disable auto-indexing and auto-removing setting the following options:
|
460
470
|
|
@@ -507,7 +517,7 @@ class MySidekiqWorker
|
|
507
517
|
if remove
|
508
518
|
# the record has likely already been removed from your database so we cannot
|
509
519
|
# use ActiveRecord#find to load it
|
510
|
-
index =
|
520
|
+
index = AlgoliaSearch.client.init_index("index_name")
|
511
521
|
index.delete_object(id)
|
512
522
|
else
|
513
523
|
# the record should be present
|
@@ -540,7 +550,7 @@ class MySidekiqWorker
|
|
540
550
|
if remove
|
541
551
|
# the record has likely already been removed from your database so we cannot
|
542
552
|
# use ActiveRecord#find to load it
|
543
|
-
index =
|
553
|
+
index = AlgoliaSearch.client.init_index("index_name")
|
544
554
|
index.delete_object(id)
|
545
555
|
else
|
546
556
|
# the record should be present
|
@@ -659,6 +669,8 @@ end
|
|
659
669
|
|
660
670
|
## Nested objects/relations
|
661
671
|
|
672
|
+
### Defining the relationship
|
673
|
+
|
662
674
|
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).
|
663
675
|
|
664
676
|
```ruby
|
@@ -684,6 +696,82 @@ class Profile < ActiveRecord::Base
|
|
684
696
|
end
|
685
697
|
```
|
686
698
|
|
699
|
+
### Propagating the change from a nested child
|
700
|
+
|
701
|
+
#### With ActiveRecord
|
702
|
+
|
703
|
+
With ActiveRecord, we'll be using `touch` and `after_touch` to achieve this.
|
704
|
+
|
705
|
+
```ruby
|
706
|
+
# app/models/app.rb
|
707
|
+
class App < ApplicationRecord
|
708
|
+
include AlgoliaSearch
|
709
|
+
|
710
|
+
belongs_to :author, class_name: :User
|
711
|
+
after_touch :index!
|
712
|
+
|
713
|
+
algoliasearch do
|
714
|
+
attribute :title
|
715
|
+
attribute :author do
|
716
|
+
author.as_json
|
717
|
+
end
|
718
|
+
end
|
719
|
+
end
|
720
|
+
|
721
|
+
# app/models/user.rb
|
722
|
+
class User < ApplicationRecord
|
723
|
+
# If your association uses belongs_to
|
724
|
+
# - use `touch: true`
|
725
|
+
# - do not define an `after_save` hook
|
726
|
+
has_many :apps, foreign_key: :author_id
|
727
|
+
|
728
|
+
after_save { apps.each(&:touch) }
|
729
|
+
end
|
730
|
+
```
|
731
|
+
|
732
|
+
#### With Sequel
|
733
|
+
|
734
|
+
With Sequel, you can use the `touch` plugin to propagate the changes:
|
735
|
+
|
736
|
+
```ruby
|
737
|
+
# app/models/app.rb
|
738
|
+
class App < Sequel::Model
|
739
|
+
include AlgoliaSearch
|
740
|
+
|
741
|
+
many_to_one :author, class: :User
|
742
|
+
|
743
|
+
plugin :timestamps
|
744
|
+
plugin :touch
|
745
|
+
|
746
|
+
algoliasearch do
|
747
|
+
attribute :title
|
748
|
+
attribute :author do
|
749
|
+
author.to_hash
|
750
|
+
end
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
# app/models/user.rb
|
755
|
+
class User < Sequel::Model
|
756
|
+
one_to_many :apps, key: :author_id
|
757
|
+
|
758
|
+
plugin :timestamps
|
759
|
+
# Can't use the associations since it won't trigger the after_save
|
760
|
+
plugin :touch
|
761
|
+
|
762
|
+
# Define the associations that need to be touched here
|
763
|
+
# Less performant, but allows for the after_save hook to trigger
|
764
|
+
def touch_associations
|
765
|
+
apps.map(&:touch)
|
766
|
+
end
|
767
|
+
|
768
|
+
def touch
|
769
|
+
super
|
770
|
+
touch_associations
|
771
|
+
end
|
772
|
+
end
|
773
|
+
```
|
774
|
+
|
687
775
|
## Custom `objectID`
|
688
776
|
|
689
777
|
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).
|
@@ -1072,27 +1160,12 @@ class User < ActiveRecord::Base
|
|
1072
1160
|
end
|
1073
1161
|
```
|
1074
1162
|
|
1075
|
-
Or you may want to mock Algolia's API calls. We provide a [WebMock](https://github.com/bblimke/webmock) sample configuration that you can use including `algolia/webmock`:
|
1076
1163
|
|
1077
|
-
|
1078
|
-
require 'algolia/webmock'
|
1164
|
+
## ❓ Troubleshooting
|
1079
1165
|
|
1080
|
-
|
1166
|
+
Encountering an issue? Before reaching out to support, we recommend heading to our [FAQ](https://www.algolia.com/doc/api-client/troubleshooting/faq/ruby/) where you will find answers for the most common issues and gotchas with the client.
|
1081
1167
|
|
1082
|
-
|
1083
|
-
WebMock.enable!
|
1084
|
-
end
|
1085
|
-
|
1086
|
-
it "shouldn't perform any API calls here" do
|
1087
|
-
User.create(name: 'My Indexed User') # mocked, no API call performed
|
1088
|
-
User.search('').should == {} # mocked, no API call performed
|
1089
|
-
end
|
1090
|
-
|
1091
|
-
after(:each) do
|
1092
|
-
WebMock.disable!
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
end
|
1096
|
-
```
|
1168
|
+
## Use the Dockerfile
|
1097
1169
|
|
1170
|
+
If you want to contribute to this project without installing all its dependencies, you can use our Docker image. Please check our [dedicated guide](DOCKER_README.MD) to learn more.
|
1098
1171
|
|
data/algoliasearch-rails.gemspec
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require File.join(File.dirname(__FILE__), 'lib', 'algoliasearch', 'version')
|
4
4
|
|
5
|
+
require 'date'
|
6
|
+
|
5
7
|
Gem::Specification.new do |s|
|
6
8
|
s.name = "algoliasearch-rails"
|
7
9
|
s.version = AlgoliaSearch::VERSION
|
@@ -12,15 +14,14 @@ Gem::Specification.new do |s|
|
|
12
14
|
s.description = "AlgoliaSearch integration to your favorite ORM"
|
13
15
|
s.email = "contact@algolia.com"
|
14
16
|
s.extra_rdoc_files = [
|
15
|
-
"
|
17
|
+
"CHANGELOG.MD",
|
16
18
|
"LICENSE",
|
17
19
|
"README.md"
|
18
20
|
]
|
19
21
|
s.files = [
|
20
22
|
".document",
|
21
23
|
".rspec",
|
22
|
-
".
|
23
|
-
"ChangeLog",
|
24
|
+
"CHANGELOG.MD",
|
24
25
|
"Gemfile",
|
25
26
|
"Gemfile.lock",
|
26
27
|
"LICENSE",
|
@@ -77,19 +78,18 @@ Gem::Specification.new do |s|
|
|
77
78
|
|
78
79
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
79
80
|
s.add_runtime_dependency(%q<json>, [">= 1.5.1"])
|
80
|
-
s.add_runtime_dependency(%q<
|
81
|
+
s.add_runtime_dependency(%q<algolia>, ["< 3.0.0"])
|
81
82
|
s.add_development_dependency(%q<will_paginate>, [">= 2.3.15"])
|
82
83
|
s.add_development_dependency(%q<kaminari>, [">= 0"])
|
83
|
-
s.add_development_dependency "travis"
|
84
84
|
s.add_development_dependency "rake"
|
85
85
|
s.add_development_dependency "rdoc"
|
86
86
|
else
|
87
87
|
s.add_dependency(%q<json>, [">= 1.5.1"])
|
88
|
-
s.add_dependency(%q<
|
88
|
+
s.add_dependency(%q<algolia>, ["< 3.0.0"])
|
89
89
|
end
|
90
90
|
else
|
91
91
|
s.add_dependency(%q<json>, [">= 1.5.1"])
|
92
|
-
s.add_dependency(%q<
|
92
|
+
s.add_dependency(%q<algolia>, ["< 3.0.0"])
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
@@ -1,12 +1,38 @@
|
|
1
1
|
module AlgoliaSearch
|
2
2
|
module Configuration
|
3
|
+
def initialize
|
4
|
+
@client = nil
|
5
|
+
end
|
6
|
+
|
3
7
|
def configuration
|
4
8
|
@@configuration || raise(NotConfigured, "Please configure AlgoliaSearch. Set AlgoliaSearch.configuration = {application_id: 'YOUR_APPLICATION_ID', api_key: 'YOUR_API_KEY'}")
|
5
9
|
end
|
6
10
|
|
7
11
|
def configuration=(configuration)
|
8
|
-
@@configuration = configuration.merge(
|
9
|
-
|
12
|
+
@@configuration = configuration.merge(
|
13
|
+
:user_agent => "Algolia for Rails (#{AlgoliaSearch::VERSION}); Rails (#{Rails::VERSION::STRING})",
|
14
|
+
:symbolize_keys => false
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
def client_opts
|
19
|
+
@@opts ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def client_opts=(opts)
|
23
|
+
@@opts = opts
|
24
|
+
end
|
25
|
+
|
26
|
+
def client
|
27
|
+
if @client.nil?
|
28
|
+
setup_client
|
29
|
+
end
|
30
|
+
|
31
|
+
@client
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup_client
|
35
|
+
@client = Algolia::Search::Client.new(Algolia::Search::Config.new(@@configuration), client_opts)
|
10
36
|
end
|
11
37
|
end
|
12
38
|
end
|
@@ -1,9 +1,14 @@
|
|
1
1
|
namespace :algoliasearch do
|
2
|
-
|
2
|
+
|
3
3
|
desc "Reindex all models"
|
4
4
|
task :reindex => :environment do
|
5
5
|
AlgoliaSearch::Utilities.reindex_all_models
|
6
6
|
end
|
7
|
+
|
8
|
+
desc "Set settings to all indexes"
|
9
|
+
task :set_all_settings => :environment do
|
10
|
+
AlgoliaSearch::Utilities.set_settings_all_models
|
11
|
+
end
|
7
12
|
|
8
13
|
desc "Clear all indexes"
|
9
14
|
task :clear_indexes => :environment do
|
@@ -2,7 +2,11 @@ module AlgoliaSearch
|
|
2
2
|
module Utilities
|
3
3
|
class << self
|
4
4
|
def get_model_classes
|
5
|
-
|
5
|
+
if Rails.application && defined?(Rails.autoloaders) && Rails.autoloaders.zeitwerk_enabled?
|
6
|
+
Zeitwerk::Loader.eager_load_all
|
7
|
+
elsif Rails.application
|
8
|
+
Rails.application.eager_load!
|
9
|
+
end
|
6
10
|
AlgoliaSearch.instance_variable_get :@included_in
|
7
11
|
end
|
8
12
|
|
@@ -25,6 +29,19 @@ module AlgoliaSearch
|
|
25
29
|
klass.algolia_reindex
|
26
30
|
end
|
27
31
|
end
|
32
|
+
|
33
|
+
def set_settings_all_models
|
34
|
+
klasses = get_model_classes
|
35
|
+
|
36
|
+
puts ''
|
37
|
+
puts "Pushing settings for #{klasses.count} models: #{klasses.to_sentence}."
|
38
|
+
puts ''
|
39
|
+
|
40
|
+
klasses.each do |klass|
|
41
|
+
puts "Pushing #{klass} settings..."
|
42
|
+
klass.algolia_set_settings
|
43
|
+
end
|
44
|
+
end
|
28
45
|
end
|
29
46
|
end
|
30
47
|
end
|