algoliasearch-rails 1.0.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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +20 -0
- data/LICENSE +22 -0
- data/README.md +167 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/algoliasearch-rails.gemspec +68 -0
- data/lib/algoliasearch-rails.rb +185 -0
- data/lib/algoliasearch/configuration.rb +12 -0
- data/lib/algoliasearch/pagination.rb +19 -0
- data/lib/algoliasearch/pagination/kaminari.rb +39 -0
- data/lib/algoliasearch/pagination/will_paginate.rb +15 -0
- data/lib/algoliasearch/railtie.rb +9 -0
- data/lib/algoliasearch/tasks/algoliasearch.rake +29 -0
- data/lib/algoliasearch/utilities.rb +22 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/utilities_spec.rb +28 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6ee0ab3d41af8ec0e02fcb7a3e2acb2c96c3b153
|
4
|
+
data.tar.gz: 654676f81691005bae28254f6be4d5f35327b69f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 245cc2983eeea49a46882d31970e217e6e585aa44027a655201b5f08a565e28df009e5ccc14c72061ed4f0365eb951012ee353d0a99ff1e2a4c54dc1d7a4e89b
|
7
|
+
data.tar.gz: fefd2ae377a28c164af784b57608c937dafc5b9c6cbfa7c5b476132cd439772d027729bac98d63aa26615c69c02a0334808c4a29c6edee5c466085b4bf38aa27
|
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem 'json', '>= 1.5.1'
|
4
|
+
gem 'algoliasearch', '>= 1.0.2'
|
5
|
+
|
6
|
+
group :test do
|
7
|
+
gem 'rspec', '>= 2.5.0'
|
8
|
+
gem 'activerecord', '>= 3.0.7'
|
9
|
+
gem 'sqlite3'
|
10
|
+
gem 'autotest'
|
11
|
+
gem 'autotest-fsevent'
|
12
|
+
gem 'redgreen'
|
13
|
+
gem 'autotest-growl'
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development do
|
17
|
+
gem 'jeweler'
|
18
|
+
gem 'will_paginate', '>= 2.3.15'
|
19
|
+
gem 'kaminari'
|
20
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Algolia
|
4
|
+
http://www.algolia.com/
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
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
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
Algolia Search for Rails
|
2
|
+
==================
|
3
|
+
|
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.
|
5
|
+
|
6
|
+
Table of Content
|
7
|
+
-------------
|
8
|
+
**Get started**
|
9
|
+
|
10
|
+
1. [Install](#install)
|
11
|
+
1. [Setup](#setup)
|
12
|
+
1. [Quick Start](#quick-start)
|
13
|
+
1. [Options](#options)
|
14
|
+
1. [Indexing](#indexing)
|
15
|
+
1. [Search settings](#search-settings)
|
16
|
+
1. [Note on testing](#note-on-testing)
|
17
|
+
|
18
|
+
Install
|
19
|
+
-------------
|
20
|
+
|
21
|
+
```sh
|
22
|
+
gem install algoliasearch-rails
|
23
|
+
```
|
24
|
+
|
25
|
+
If you are using Rails 3, add the gem to your <code>Gemfile</code>:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem "algoliasearch-rails"
|
29
|
+
```
|
30
|
+
|
31
|
+
And run:
|
32
|
+
|
33
|
+
```sh
|
34
|
+
bundle install
|
35
|
+
```
|
36
|
+
|
37
|
+
Setup
|
38
|
+
-------------
|
39
|
+
Create a new file <code>config/initializers/algoliasearch.rb</code> to setup your <code>APPLICATION_ID</code> and <code>API_KEY</code>.
|
40
|
+
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
AlgoliaSearch.configuration = { application_id: 'YourApplicationID', api_key: 'YourAPIKey' }
|
44
|
+
```
|
45
|
+
|
46
|
+
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:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
AlgoliaSearch.configuration = { application_id: 'YourApplicationID', api_key: 'YourAPIKey', pagination_backend: :will_paginate }
|
50
|
+
```
|
51
|
+
|
52
|
+
Quick Start
|
53
|
+
-------------
|
54
|
+
|
55
|
+
The following code will create a <code>contact</code> index and add search capabilities to your <code>Contact</code> model:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Contact < ActiveRecord::Base
|
59
|
+
include AlgoliaSearch
|
60
|
+
|
61
|
+
algoliasearch do
|
62
|
+
attribute :first_name, :last_name, :email
|
63
|
+
end
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
You can either specify the attributes to send (here we restrict to <code>:first_name, :last_name, :email</code>) or not (in that case, all attributes are sent).
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class Product < ActiveRecord::Base
|
71
|
+
include AlgoliaSearch
|
72
|
+
|
73
|
+
algoliasearch do
|
74
|
+
# all attributes will be sent
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
p Contact.search("jon doe")
|
81
|
+
```
|
82
|
+
|
83
|
+
Options
|
84
|
+
----------
|
85
|
+
|
86
|
+
Each time a record is saved; it will be - synchronously - indexed. In the other hand, each time a record is destroyed, it will be - synchronoulsy - removed from the index.
|
87
|
+
|
88
|
+
You can disable auto-indexing and auto-removing setting the following options:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
class Contact < ActiveRecord::Base
|
92
|
+
include AlgoliaSearch
|
93
|
+
|
94
|
+
algoliasearch auto_index: false, auto_remove: false do
|
95
|
+
attribute :first_name, :last_name, :email
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
You can force indexing and removing to be asynchronous by setting the following option:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
class Contact < ActiveRecord::Base
|
104
|
+
include AlgoliaSearch
|
105
|
+
|
106
|
+
algoliasearch synchronous: false do
|
107
|
+
attribute :first_name, :last_name, :email
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
Indexing
|
113
|
+
---------
|
114
|
+
|
115
|
+
You can trigger indexing using the <code>index!</code> instance method.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
c = Contact.create!(params[:contact])
|
119
|
+
c.index!
|
120
|
+
```
|
121
|
+
|
122
|
+
And trigger index removing using the <code>remove_from_index!</code> instance method.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
c.remove_from_index!
|
126
|
+
c.destroy
|
127
|
+
```
|
128
|
+
|
129
|
+
To reindex all your records, use the <code>reindex!</code> class method:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
Contact.reindex!
|
133
|
+
```
|
134
|
+
|
135
|
+
To clear an index, use the <code>clear_index!</code> class method:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
Contact.clear_index!
|
139
|
+
```
|
140
|
+
|
141
|
+
|
142
|
+
Search settings
|
143
|
+
----------
|
144
|
+
|
145
|
+
All [settings](https://github.com/algolia/algoliasearch-client-ruby#index-settings) can be specified either statically in your model or dynamically at search time using [search options](https://github.com/algolia/algoliasearch-client-ruby#search):
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class Contact < ActiveRecord::Base
|
149
|
+
include AlgoliaSearch
|
150
|
+
|
151
|
+
algoliasearch auto_index: false, auto_remove: false do
|
152
|
+
attribute :first_name, :last_name, :email
|
153
|
+
minWordSizeForApprox1 2
|
154
|
+
minWordSizeForApprox2 5
|
155
|
+
hitsPerPage 42
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
p Contact.search("jon doe", hitsPerPage: 5, page: 2)
|
162
|
+
```
|
163
|
+
|
164
|
+
Note on testing
|
165
|
+
-----------------
|
166
|
+
|
167
|
+
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.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "algoliasearch-rails"
|
8
|
+
gem.summary = %Q{AlgoliaSearch integration to your favorite ORM}
|
9
|
+
gem.description = %Q{AlgoliaSearch integration to your favorite ORM}
|
10
|
+
gem.homepage = "http://github.com/algolia/algoliasearch-rails"
|
11
|
+
gem.email = "contact@algolia.com"
|
12
|
+
gem.authors = ["Algolia"]
|
13
|
+
gem.files.exclude 'spec/integration_spec.rb'
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::RubygemsDotOrgTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require "rspec/core/rake_task"
|
22
|
+
# RSpec 2.0
|
23
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
24
|
+
spec.pattern = 'spec/{algoliasearch,utilities}_spec.rb'
|
25
|
+
spec.rspec_opts = ['--backtrace']
|
26
|
+
end
|
27
|
+
task :default => :spec
|
28
|
+
|
29
|
+
desc "Generate code coverage"
|
30
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
31
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
32
|
+
t.rcov = true
|
33
|
+
t.rcov_opts = ['--exclude', 'spec']
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Run Integration Specs"
|
37
|
+
RSpec::Core::RakeTask.new(:integration) do |t|
|
38
|
+
t.pattern = "spec/integration_spec.rb" # don't need this, it's default.
|
39
|
+
t.rcov = true
|
40
|
+
t.rcov_opts = ['--exclude', 'spec']
|
41
|
+
end
|
42
|
+
|
43
|
+
require 'rdoc/task'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "AlgoliaSearch Rails #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "algoliasearch-rails"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Algolia"]
|
12
|
+
s.date = "2013-09-18"
|
13
|
+
s.description = "AlgoliaSearch integration to your favorite ORM"
|
14
|
+
s.email = "contact@algolia.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"algoliasearch-rails.gemspec",
|
28
|
+
"lib/algoliasearch-rails.rb",
|
29
|
+
"lib/algoliasearch/configuration.rb",
|
30
|
+
"lib/algoliasearch/pagination.rb",
|
31
|
+
"lib/algoliasearch/pagination/kaminari.rb",
|
32
|
+
"lib/algoliasearch/pagination/will_paginate.rb",
|
33
|
+
"lib/algoliasearch/railtie.rb",
|
34
|
+
"lib/algoliasearch/tasks/algoliasearch.rake",
|
35
|
+
"lib/algoliasearch/utilities.rb",
|
36
|
+
"spec/spec_helper.rb",
|
37
|
+
"spec/utilities_spec.rb"
|
38
|
+
]
|
39
|
+
s.homepage = "http://github.com/algolia/algoliasearch-rails"
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = "2.0.3"
|
42
|
+
s.summary = "AlgoliaSearch integration to your favorite ORM"
|
43
|
+
|
44
|
+
if s.respond_to? :specification_version then
|
45
|
+
s.specification_version = 4
|
46
|
+
|
47
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
|
+
s.add_runtime_dependency(%q<json>, [">= 1.5.1"])
|
49
|
+
s.add_runtime_dependency(%q<algoliasearch>, [">= 1.0.2"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<will_paginate>, [">= 2.3.15"])
|
52
|
+
s.add_development_dependency(%q<kaminari>, [">= 0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<json>, [">= 1.5.1"])
|
55
|
+
s.add_dependency(%q<algoliasearch>, [">= 1.0.2"])
|
56
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
57
|
+
s.add_dependency(%q<will_paginate>, [">= 2.3.15"])
|
58
|
+
s.add_dependency(%q<kaminari>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<json>, [">= 1.5.1"])
|
62
|
+
s.add_dependency(%q<algoliasearch>, [">= 1.0.2"])
|
63
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
64
|
+
s.add_dependency(%q<will_paginate>, [">= 2.3.15"])
|
65
|
+
s.add_dependency(%q<kaminari>, [">= 0"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,185 @@
|
|
1
|
+
begin
|
2
|
+
require "rubygems"
|
3
|
+
require "bundler"
|
4
|
+
|
5
|
+
Bundler.setup :default
|
6
|
+
rescue => e
|
7
|
+
puts "AlgoliaSearch: #{e.message}"
|
8
|
+
end
|
9
|
+
require 'algoliasearch'
|
10
|
+
|
11
|
+
require 'algoliasearch/utilities'
|
12
|
+
|
13
|
+
if defined? Rails
|
14
|
+
begin
|
15
|
+
require 'algoliasearch/railtie'
|
16
|
+
rescue LoadError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module AlgoliaSearch
|
21
|
+
|
22
|
+
class NotConfigured < StandardError; end
|
23
|
+
class BadConfiguration < StandardError; end
|
24
|
+
class NoBlockGiven < StandardError; end
|
25
|
+
|
26
|
+
autoload :Configuration, 'algoliasearch/configuration'
|
27
|
+
extend Configuration
|
28
|
+
|
29
|
+
autoload :Pagination, 'algoliasearch/pagination'
|
30
|
+
|
31
|
+
class << self
|
32
|
+
attr_reader :included_in
|
33
|
+
|
34
|
+
def included(klass)
|
35
|
+
@included_in ||= []
|
36
|
+
@included_in << klass
|
37
|
+
@included_in.uniq!
|
38
|
+
|
39
|
+
klass.send :include, InstanceMethods
|
40
|
+
klass.extend ClassMethods
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
class IndexOptions
|
46
|
+
|
47
|
+
# AlgoliaSearch settings
|
48
|
+
OPTIONS = [:attributesToIndex, :minWordSizeForApprox1,
|
49
|
+
:minWordSizeForApprox2, :hitsPerPage, :attributesToRetrieve,
|
50
|
+
:attributesToHighlight, :attributesToSnippet, :attributesToIndex,
|
51
|
+
:ranking, :customRanking, :queryType]
|
52
|
+
attr_accessor *OPTIONS
|
53
|
+
|
54
|
+
# attributes to consider
|
55
|
+
attr_accessor :attributes
|
56
|
+
|
57
|
+
def initialize(block)
|
58
|
+
instance_exec(&block) if block
|
59
|
+
end
|
60
|
+
|
61
|
+
def attribute(*names)
|
62
|
+
self.attributes ||= []
|
63
|
+
self.attributes += names
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_settings
|
67
|
+
settings = {}
|
68
|
+
OPTIONS.each do |k|
|
69
|
+
v = send(k)
|
70
|
+
settings[k] = v if !v.nil?
|
71
|
+
end
|
72
|
+
settings
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# these are the class methods added when AlgoliaSearch is included
|
77
|
+
module ClassMethods
|
78
|
+
def algoliasearch(options = {}, &block)
|
79
|
+
@index_options = IndexOptions.new(block_given? ? Proc.new : nil)
|
80
|
+
attr_accessor :highlight_result
|
81
|
+
|
82
|
+
unless options[:synchronous] == false
|
83
|
+
before_save :mark_synchronous if respond_to?(:before_save)
|
84
|
+
end
|
85
|
+
unless options[:auto_index] == false
|
86
|
+
before_save :mark_for_auto_indexing if respond_to?(:before_save)
|
87
|
+
after_save :perform_index_tasks if respond_to?(:after_save)
|
88
|
+
end
|
89
|
+
unless options[:auto_remove] == false
|
90
|
+
after_destroy { |searchable| searchable.remove_from_index! } if respond_to?(:after_destroy)
|
91
|
+
end
|
92
|
+
|
93
|
+
@options = { type: model_name, per_page: @index_options.hitsPerPage || 10, page: 1 }.merge(options)
|
94
|
+
init
|
95
|
+
end
|
96
|
+
|
97
|
+
def reindex!(batch_size = 1000, synchronous = true)
|
98
|
+
find_in_batches(batch_size: batch_size) do |group|
|
99
|
+
objects = group.map { |o| attributes(o).merge 'objectID' => o.id.to_s }
|
100
|
+
if synchronous == true
|
101
|
+
@index.save_objects!(objects)
|
102
|
+
else
|
103
|
+
@index.save_objects(objects)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def index!(object, synchronous = true)
|
109
|
+
if synchronous
|
110
|
+
@index.add_object!(attributes(object), object.id.to_s)
|
111
|
+
else
|
112
|
+
@index.add_object(attributes(object), object.id.to_s)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def remove_from_index!(object, synchronous = true)
|
117
|
+
if synchronous
|
118
|
+
@index.delete_object!(object.id.to_s)
|
119
|
+
else
|
120
|
+
@index.delete_object(object.id.to_s)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def clear_index!
|
125
|
+
@index.delete
|
126
|
+
@index = nil
|
127
|
+
init
|
128
|
+
end
|
129
|
+
|
130
|
+
def search(q, settings = {})
|
131
|
+
json = @index.search(q, Hash[settings.map { |k,v| [k.to_s, v.to_s] }])
|
132
|
+
results = json['hits'].map do |hit|
|
133
|
+
o = Object.const_get(@options[:type]).find(hit['objectID'])
|
134
|
+
o.highlight_result = hit['_highlightResult']
|
135
|
+
o
|
136
|
+
end
|
137
|
+
AlgoliaSearch::Pagination.create(results, json['nbHits'].to_i, @options)
|
138
|
+
end
|
139
|
+
|
140
|
+
def init
|
141
|
+
@index ||= Algolia::Index.new(model_name)
|
142
|
+
@index.set_settings(@index_options.to_settings)
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def attributes(object)
|
148
|
+
return object.attributes if @index_options.attributes.nil? or @index_options.attributes.length == 0
|
149
|
+
Hash[@index_options.attributes.map { |attr| [attr.to_s, object.send(attr)] }]
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# these are the instance methods included
|
155
|
+
module InstanceMethods
|
156
|
+
def index!
|
157
|
+
self.class.index!(self, synchronous?)
|
158
|
+
end
|
159
|
+
|
160
|
+
def remove_from_index!
|
161
|
+
self.class.remove_from_index!(self, synchronous?)
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def synchronous?
|
167
|
+
@synchronous.nil? || @synchronous == true
|
168
|
+
end
|
169
|
+
|
170
|
+
def mark_synchronous
|
171
|
+
@synchronous = true
|
172
|
+
end
|
173
|
+
|
174
|
+
def mark_for_auto_indexing
|
175
|
+
@auto_indexing = true
|
176
|
+
end
|
177
|
+
|
178
|
+
def perform_index_tasks
|
179
|
+
return if !@auto_indexing
|
180
|
+
index!
|
181
|
+
remove_instance_variable :@auto_indexing
|
182
|
+
remove_instance_variable :@synchronous
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module AlgoliaSearch
|
2
|
+
module Configuration
|
3
|
+
def configuration
|
4
|
+
@@configuration || raise(NotConfigured, "Please configure AlgoliaSearch. Set AlgoliaSearch.configuration = {application_id: 'YOUR_APPLICATION_ID', api_key: 'YOUR_API_KEY'}")
|
5
|
+
end
|
6
|
+
|
7
|
+
def configuration=(configuration)
|
8
|
+
@@configuration = configuration
|
9
|
+
Algolia.init application_id: @@configuration[:application_id], api_key: @@configuration[:api_key]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AlgoliaSearch
|
2
|
+
module Pagination
|
3
|
+
|
4
|
+
autoload :WillPaginate, 'algoliasearch/pagination/will_paginate'
|
5
|
+
autoload :Kaminari, 'algoliasearch/pagination/kaminari'
|
6
|
+
|
7
|
+
def self.create(results, total_hits, options = {})
|
8
|
+
return results if AlgoliaSearch.configuration[:pagination_backend].nil?
|
9
|
+
begin
|
10
|
+
backend = AlgoliaSearch.configuration[:pagination_backend].to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } # classify pagination backend name
|
11
|
+
page = Object.const_get(:AlgoliaSearch).const_get(:Pagination).const_get(backend).create(results, total_hits, options)
|
12
|
+
page
|
13
|
+
rescue NameError
|
14
|
+
raise(BadConfiguration, "Unknown pagination backend")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
unless defined? Kaminari
|
2
|
+
raise(AlgoliaSearch::BadConfiguration, "AlgoliaSearch: Please add 'kaminari' to your Gemfile to use kaminari pagination backend")
|
3
|
+
end
|
4
|
+
|
5
|
+
module AlgoliaSearch
|
6
|
+
module Pagination
|
7
|
+
class Kaminari < Array
|
8
|
+
include ::Kaminari::ConfigurationMethods::ClassMethods
|
9
|
+
include ::Kaminari::PageScopeMethods
|
10
|
+
|
11
|
+
attr_reader :limit_value, :offset_value, :total_count
|
12
|
+
|
13
|
+
def initialize(original_array, limit_val, offset_val, total_count)
|
14
|
+
@limit_value = limit_val || default_per_page
|
15
|
+
@offset_value, @total_count = offset_val, total_count
|
16
|
+
super(original_array)
|
17
|
+
end
|
18
|
+
|
19
|
+
def page(num = 1)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def limit(num)
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def current_page
|
28
|
+
offset_value+1
|
29
|
+
end
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def create(results, total_hits, options = {})
|
33
|
+
instance = new(results, options[:per_page], options[:page]-1, total_hits)
|
34
|
+
instance
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'will_paginate/collection'
|
3
|
+
rescue LoadError
|
4
|
+
raise(AlgoliaSearch::BadConfiguration, "AlgoliaSearch: Please add 'will_paginate' to your Gemfile to use will_paginate pagination backend")
|
5
|
+
end
|
6
|
+
|
7
|
+
module AlgoliaSearch
|
8
|
+
module Pagination
|
9
|
+
class WillPaginate
|
10
|
+
def self.create(results, total_hits, options = {})
|
11
|
+
::WillPaginate::Collection.create(options[:page], options[:per_page], total_hits) { |pager| pager.replace results }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace :algoliasearch do
|
2
|
+
|
3
|
+
desc "Reindex all models"
|
4
|
+
task :reindex => :environment do
|
5
|
+
puts "reindexing all models"
|
6
|
+
load_models
|
7
|
+
AlgoliaSearch::Utilities.reindex_all_models
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Clear all indexes"
|
11
|
+
task :clear_indexes => :environment do
|
12
|
+
puts "clearing all indexes"
|
13
|
+
load_models
|
14
|
+
AlgoliaSearch::Utilities.clear_all_indexes
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_models
|
18
|
+
app_root = Rails.root
|
19
|
+
dirs = ["#{app_root}/app/models/"] + Dir.glob("#{app_root}/vendor/plugins/*/app/models/")
|
20
|
+
|
21
|
+
dirs.each do |base|
|
22
|
+
Dir["#{base}**/*.rb"].each do |file|
|
23
|
+
model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
|
24
|
+
next if model_name.nil?
|
25
|
+
model_name.camelize.constantize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AlgoliaSearch
|
2
|
+
module Utilities
|
3
|
+
class << self
|
4
|
+
def get_model_classes
|
5
|
+
AlgoliaSearch.included_in ? AlgoliaSearch.included_in : []
|
6
|
+
end
|
7
|
+
|
8
|
+
def clear_all_indexes
|
9
|
+
get_model_classes.each do |klass|
|
10
|
+
klass.clear_index!
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def reindex_all_models
|
15
|
+
get_model_classes.each do |klass|
|
16
|
+
klass.reindex!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
Bundler.setup :test
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
|
7
|
+
require 'algoliasearch-rails'
|
8
|
+
require 'rspec'
|
9
|
+
|
10
|
+
raise "missing ALGOLIA_APPLICATION_ID or ALGOLIA_API_KEY environment variables" if ENV['ALGOLIA_APPLICATION_ID'].nil? || ENV['ALGOLIA_API_KEY'].nil?
|
11
|
+
|
12
|
+
AlgoliaSearch.configuration = { application_id: ENV['ALGOLIA_APPLICATION_ID'], api_key: ENV['ALGOLIA_API_KEY'] }
|
13
|
+
|
14
|
+
RSpec.configure do |c|
|
15
|
+
c.mock_with :rspec
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
describe AlgoliaSearch::Utilities do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@included_in = AlgoliaSearch.instance_variable_get :@included_in
|
7
|
+
AlgoliaSearch.instance_variable_set :@included_in, []
|
8
|
+
|
9
|
+
class Dummy
|
10
|
+
include AlgoliaSearch
|
11
|
+
|
12
|
+
def self.model_name
|
13
|
+
"dummy"
|
14
|
+
end
|
15
|
+
|
16
|
+
algoliasearch
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:each) do
|
21
|
+
AlgoliaSearch.instance_variable_set :@included_in, @included_in
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should get the models where AlgoliaSearch module was included" do
|
25
|
+
(AlgoliaSearch::Utilities.get_model_classes - [Dummy]).should == []
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: algoliasearch-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Algolia
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-09-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.5.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.5.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: algoliasearch
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: jeweler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: will_paginate
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.3.15
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.3.15
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: kaminari
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: AlgoliaSearch integration to your favorite ORM
|
84
|
+
email: contact@algolia.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files:
|
88
|
+
- LICENSE
|
89
|
+
- README.md
|
90
|
+
files:
|
91
|
+
- .document
|
92
|
+
- .rspec
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- VERSION
|
98
|
+
- algoliasearch-rails.gemspec
|
99
|
+
- lib/algoliasearch-rails.rb
|
100
|
+
- lib/algoliasearch/configuration.rb
|
101
|
+
- lib/algoliasearch/pagination.rb
|
102
|
+
- lib/algoliasearch/pagination/kaminari.rb
|
103
|
+
- lib/algoliasearch/pagination/will_paginate.rb
|
104
|
+
- lib/algoliasearch/railtie.rb
|
105
|
+
- lib/algoliasearch/tasks/algoliasearch.rake
|
106
|
+
- lib/algoliasearch/utilities.rb
|
107
|
+
- spec/spec_helper.rb
|
108
|
+
- spec/utilities_spec.rb
|
109
|
+
homepage: http://github.com/algolia/algoliasearch-rails
|
110
|
+
licenses: []
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.0.3
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: AlgoliaSearch integration to your favorite ORM
|
132
|
+
test_files: []
|