activesearch 0.2.0 → 0.3.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 +4 -4
- data/.rspec +2 -0
- data/Rakefile +19 -1
- data/activesearch.gemspec +5 -4
- data/lib/activesearch/algolia/worker.rb +2 -2
- data/lib/activesearch/algolia.rb +31 -19
- data/lib/activesearch/base.rb +18 -6
- data/lib/activesearch/mongoid/index.rb +115 -0
- data/lib/activesearch/mongoid.rb +24 -7
- data/lib/activesearch/result.rb +9 -2
- data/lib/activesearch/version.rb +1 -1
- data/spec/engines/algolia_spec.rb +32 -0
- data/spec/{base_spec.rb → engines/base_spec.rb} +13 -13
- data/spec/engines/mongoid_spec.rb +56 -0
- data/spec/models/algolia.rb +4 -6
- data/spec/models/elastic_search.rb +6 -9
- data/spec/models/mongoid.rb +16 -22
- data/spec/spec_helper.rb +43 -53
- data/spec/support/active_mimic.rb +56 -0
- data/spec/support/setup_engine.rb +53 -0
- data/spec/support/shared_examples_for_engines.rb +63 -0
- metadata +33 -12
- data/lib/activesearch/mongoid/model.rb +0 -67
- data/spec/algolia_spec.rb +0 -29
- data/spec/engines_spec.rb +0 -90
- data/spec/mongoid_spec.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b24050eefed5b21eb1b0d085fa964effdc06c2d8
|
4
|
+
data.tar.gz: 780df5ddeb72407c972869ab11a9a6e015018554
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1e5576e03f3f0ae6a610ddef63bf3c661e68520ef8fdae55ca4e98c9676f14fb038de8088b416c59b085515ea4568aa5b58500085003bae87ee80c375e66cc7
|
7
|
+
data.tar.gz: f1caac8c129064500ec93a3f13f7854ab83f698ed7e27f8729ae9fc21cf2a2a999a23fd75663304590bb1490ef0e979e2f3a2fff4ff7abd71b4aa884eb7e23c1
|
data/.rspec
ADDED
data/Rakefile
CHANGED
@@ -1 +1,19 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler/setup'
|
6
|
+
|
7
|
+
require 'rake'
|
8
|
+
require 'rspec'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
require 'rubygems/package_task'
|
11
|
+
|
12
|
+
# === Gems install tasks ===
|
13
|
+
Bundler::GemHelper.install_tasks
|
14
|
+
|
15
|
+
RSpec::Core::RakeTask.new('spec') do |spec|
|
16
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
17
|
+
end
|
18
|
+
|
19
|
+
task :default => :spec
|
data/activesearch.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'activesearch/version'
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "activesearch"
|
8
8
|
gem.version = ActiveSearch::VERSION
|
9
|
-
gem.authors = [
|
10
|
-
gem.email = [
|
9
|
+
gem.authors = ['Rodrigo Alvarez', 'Didier Lafforgue']
|
10
|
+
gem.email = ['papipo@gmail.com', 'didier.lafforgue@gmail.com']
|
11
11
|
gem.description = %q{ORM agnostic full text search}
|
12
12
|
gem.summary = %q{ActiveSearch lets you plug in a ruby module in any class that will allow you to do full text searches.}
|
13
13
|
gem.homepage = ""
|
@@ -16,15 +16,16 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
|
-
|
19
|
+
|
20
20
|
gem.add_dependency "activesupport"
|
21
21
|
gem.add_dependency "sucker_punch"
|
22
22
|
gem.add_dependency "actionpack"
|
23
|
-
|
23
|
+
|
24
24
|
gem.add_development_dependency "rspec"
|
25
25
|
gem.add_development_dependency "rspec-mocks"
|
26
26
|
gem.add_development_dependency "active_attr"
|
27
27
|
gem.add_development_dependency "mongoid", "~> 3"
|
28
|
+
gem.add_development_dependency "database_cleaner", "~> 0.9.1"
|
28
29
|
gem.add_development_dependency "tire"
|
29
30
|
gem.add_development_dependency "parallel_tests"
|
30
31
|
gem.add_development_dependency "httparty"
|
@@ -2,7 +2,7 @@ require "sucker_punch"
|
|
2
2
|
|
3
3
|
class ActiveSearch::Algolia::Worker
|
4
4
|
include SuckerPunch::Job
|
5
|
-
|
5
|
+
|
6
6
|
def perform(msg)
|
7
7
|
begin
|
8
8
|
case msg[:task]
|
@@ -10,7 +10,7 @@ class ActiveSearch::Algolia::Worker
|
|
10
10
|
::ActiveSearch::Algolia::Client.new.save(msg[:id], msg[:doc])
|
11
11
|
when :deindex
|
12
12
|
client = ::ActiveSearch::Algolia::Client.new
|
13
|
-
client.query("", tags: "original_id:#{msg[:id]}")["hits"].each do |hit|
|
13
|
+
client.query("", tags: "original_type:#{msg[:type]},original_id:#{msg[:id]}")["hits"].each do |hit|
|
14
14
|
client.delete(hit["objectID"])
|
15
15
|
end
|
16
16
|
end
|
data/lib/activesearch/algolia.rb
CHANGED
@@ -4,13 +4,21 @@ require "activesearch/base"
|
|
4
4
|
require "activesearch/proxy"
|
5
5
|
|
6
6
|
module ActiveSearch
|
7
|
+
|
7
8
|
def self.search(text, conditions = {}, options = {})
|
9
|
+
locale = options[:locale] || I18n.locale
|
10
|
+
conditions[:locale] ||= locale
|
11
|
+
|
8
12
|
Proxy.new(text, conditions, options) do |text, conditions|
|
9
13
|
Algolia::Client.new.query(text, tags: conditions_to_tags(conditions))["hits"].map! do |hit|
|
10
14
|
if hit["_tags"]
|
11
15
|
hit["_tags"].each do |tag|
|
12
|
-
|
13
|
-
|
16
|
+
# preserve other ":" characters
|
17
|
+
_segments = tag.split(':')
|
18
|
+
|
19
|
+
unless _segments.empty? || _segments[1..-1].empty?
|
20
|
+
hit[_segments.first] = _segments[1..-1].join(':')
|
21
|
+
end
|
14
22
|
end
|
15
23
|
hit.delete("_tags")
|
16
24
|
end
|
@@ -20,8 +28,9 @@ module ActiveSearch
|
|
20
28
|
end
|
21
29
|
|
22
30
|
protected
|
31
|
+
|
23
32
|
def self.conditions_to_tags(conditions)
|
24
|
-
conditions.
|
33
|
+
conditions.map { |c| c.join(':') }.join(',')
|
25
34
|
end
|
26
35
|
|
27
36
|
module Algolia
|
@@ -33,32 +42,35 @@ module ActiveSearch
|
|
33
42
|
|
34
43
|
protected
|
35
44
|
def reindex
|
36
|
-
Worker.new.async.perform(task: :reindex, id: "#{indexable_id}_#{
|
45
|
+
Worker.new.async.perform(task: :reindex, id: "#{indexable_id}_#{search_locale}", doc: to_indexable)
|
37
46
|
end
|
38
47
|
|
39
48
|
def deindex
|
40
|
-
Worker.new.async.perform(task: :deindex, id:
|
49
|
+
Worker.new.async.perform(task: :deindex, id: self.id, type: self.class.to_s)
|
41
50
|
end
|
42
51
|
|
43
52
|
def to_indexable
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
53
|
+
{}.tap do |doc|
|
54
|
+
_locale = search_locale
|
55
|
+
|
56
|
+
search_fields.each do |field|
|
57
|
+
if content = send(field)
|
58
|
+
doc[field.to_s] = if content.is_a?(Hash) && content.has_key?(_locale)
|
59
|
+
ActiveSearch.strip_tags(content[_locale])
|
60
|
+
else
|
61
|
+
ActiveSearch.strip_tags(content)
|
62
|
+
end
|
51
63
|
end
|
52
64
|
end
|
53
|
-
end
|
54
65
|
|
55
|
-
|
56
|
-
|
57
|
-
|
66
|
+
(Array(search_options[:store]) - search_fields).each do |field|
|
67
|
+
doc["_tags"] ||= []
|
68
|
+
doc["_tags"] << "#{field}:#{self.send(field)}"
|
69
|
+
end
|
70
|
+
doc["_tags"] << "locale:#{_locale}"
|
71
|
+
doc["_tags"] << "original_type:#{self.class.to_s}"
|
72
|
+
doc["_tags"] << "original_id:#{self.id}"
|
58
73
|
end
|
59
|
-
doc["_tags"] << "locale:#{I18n.locale}"
|
60
|
-
doc["_tags"] << "original_id:#{indexable_id}"
|
61
|
-
doc
|
62
74
|
end
|
63
75
|
end
|
64
76
|
end
|
data/lib/activesearch/base.rb
CHANGED
@@ -7,25 +7,37 @@ module ActiveSearch
|
|
7
7
|
value.gsub(/<\/?[^>]*>/, '')
|
8
8
|
when Hash
|
9
9
|
value.each_with_object({}) { |(k,v),h| h[k] = strip_tags(v) }
|
10
|
+
when Array
|
11
|
+
value.map { |v| strip_tags(v) }
|
10
12
|
else
|
11
13
|
value
|
12
14
|
end
|
13
15
|
end
|
14
|
-
|
16
|
+
|
15
17
|
module Base
|
16
18
|
def self.included(parent)
|
17
19
|
parent.extend ClassMethods
|
18
20
|
parent.class_attribute :search_parameters, instance_reader: false
|
19
21
|
end
|
20
|
-
|
22
|
+
|
21
23
|
def search_options
|
22
24
|
search_parameters.last.is_a?(Hash) ? search_parameters.last : {}
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
def search_fields
|
26
28
|
search_parameters.last.is_a?(Hash) ? search_parameters[0...-1] : search_parameters
|
27
29
|
end
|
28
|
-
|
30
|
+
|
31
|
+
def search_locale
|
32
|
+
search_locale = search_options[:locale] || I18n.locale.to_s
|
33
|
+
|
34
|
+
if search_locale.respond_to?(:call)
|
35
|
+
search_locale.call
|
36
|
+
else
|
37
|
+
search_locale
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
29
41
|
def search_parameters
|
30
42
|
if self.class.search_parameters.is_a?(Symbol)
|
31
43
|
self.send(self.class.search_parameters)
|
@@ -33,14 +45,14 @@ module ActiveSearch
|
|
33
45
|
self.class.search_parameters
|
34
46
|
end
|
35
47
|
end
|
36
|
-
|
48
|
+
|
37
49
|
module ClassMethods
|
38
50
|
def search_by(params, conditions = {})
|
39
51
|
after_save :reindex, conditions
|
40
52
|
after_destroy :deindex, conditions
|
41
53
|
self.search_parameters = params
|
42
54
|
end
|
43
|
-
|
55
|
+
|
44
56
|
end
|
45
57
|
end
|
46
58
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module ActiveSearch
|
2
|
+
module Mongoid
|
3
|
+
class Index
|
4
|
+
|
5
|
+
include ::Mongoid::Document
|
6
|
+
|
7
|
+
## fields ##
|
8
|
+
field :original_type, type: String
|
9
|
+
field :original_id, type: Moped::BSON::ObjectId
|
10
|
+
field :language, type: String
|
11
|
+
field :locale, type: String
|
12
|
+
field :content, type: Array
|
13
|
+
field :stored, type: Hash, default: {}
|
14
|
+
alias_method :to_hash, :stored
|
15
|
+
|
16
|
+
## indexes ##
|
17
|
+
index({ content: 'text', locale: 1 })
|
18
|
+
index({ original_type: 1, original_id: 1, locale: 1 }, unique: true)
|
19
|
+
|
20
|
+
## methods ##
|
21
|
+
|
22
|
+
def store_language(original)
|
23
|
+
self.locale = original.search_locale
|
24
|
+
self.language = self.class.locale_to_language(self.locale)
|
25
|
+
end
|
26
|
+
|
27
|
+
def store_fields(original)
|
28
|
+
self.stored = {}
|
29
|
+
|
30
|
+
fields = (original.search_fields + (original.search_options[:store] || [])).uniq
|
31
|
+
|
32
|
+
fields.each do |f|
|
33
|
+
if original.send(f).present?
|
34
|
+
self.stored[f] = ActiveSearch.strip_tags(original.send(f))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def refresh_content(original)
|
40
|
+
self.content = original.to_indexable.values.flatten
|
41
|
+
end
|
42
|
+
|
43
|
+
## class methods ##
|
44
|
+
|
45
|
+
def self.search(query, conditions = {})
|
46
|
+
language = self.locale_to_language(conditions[:locale] || I18n.locale)
|
47
|
+
|
48
|
+
filter = {}
|
49
|
+
conditions.each do |key, value|
|
50
|
+
if key == :locale
|
51
|
+
filter['locale'] = value.to_s
|
52
|
+
else
|
53
|
+
filter["stored.#{key}"] = value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
session = ::Mongoid.session('default')
|
58
|
+
results = session.command({
|
59
|
+
'text' => collection.name,
|
60
|
+
'search' => query,
|
61
|
+
'language' => language,
|
62
|
+
'filter' => filter
|
63
|
+
})
|
64
|
+
if results.has_key?('results')
|
65
|
+
results['results'].map do |result|
|
66
|
+
result['obj']['stored'].merge(result['obj'].slice('locale', 'original_type', 'original_id'))
|
67
|
+
end
|
68
|
+
else
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.deindex(original)
|
74
|
+
# delete the records in all the locales
|
75
|
+
self.where(original_type: original.class.to_s, original_id: original.id).destroy
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.reindex(original, fields, options)
|
79
|
+
# re-index only in the current locale (unless another locale has been specified)
|
80
|
+
locale = original.search_locale
|
81
|
+
|
82
|
+
# find the exact index scoped by the locale or build a new one
|
83
|
+
doc = find_or_initialize_by(original_type: original.class.to_s, original_id: original.id, locale: locale)
|
84
|
+
|
85
|
+
doc.store_language(original)
|
86
|
+
doc.store_fields(original) #, fields, options)
|
87
|
+
doc.refresh_content(original)
|
88
|
+
|
89
|
+
# save it (create or update it)
|
90
|
+
doc.save
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.locale_to_language(locale)
|
94
|
+
{
|
95
|
+
dk: 'danish',
|
96
|
+
nl: 'dutch',
|
97
|
+
en: 'english',
|
98
|
+
fi: 'finnish',
|
99
|
+
fr: 'french',
|
100
|
+
de: 'german',
|
101
|
+
hu: 'hungarian',
|
102
|
+
it: 'italian',
|
103
|
+
nb: 'norwegian',
|
104
|
+
br: 'portuguese',
|
105
|
+
pt: 'portuguese',
|
106
|
+
ro: 'romanian',
|
107
|
+
ru: 'russian',
|
108
|
+
es: 'spanish',
|
109
|
+
se: 'swedish',
|
110
|
+
tr: 'turkish'
|
111
|
+
}[locale.to_sym] || 'english'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/activesearch/mongoid.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'activesearch/base'
|
2
2
|
require 'activesearch/proxy'
|
3
|
-
require 'activesearch/mongoid/
|
3
|
+
require 'activesearch/mongoid/index'
|
4
4
|
|
5
5
|
module ActiveSearch
|
6
6
|
|
7
7
|
def self.search(text, conditions = {}, options = {})
|
8
|
+
locale = options[:locale] || I18n.locale
|
9
|
+
conditions[:locale] ||= locale
|
10
|
+
|
8
11
|
Proxy.new(text, conditions, options) do |text, conditions|
|
9
|
-
text
|
10
|
-
conditions.keys.each { |k| conditions["_stored.#{k}"] = conditions.delete(k) }
|
11
|
-
conditions.merge!(:_keywords.in => text + text.map { |word| "#{I18n.locale}:#{word}"})
|
12
|
-
Mongoid::Model.where(conditions)
|
12
|
+
ActiveSearch::Mongoid::Index.search(text, conditions)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -20,13 +20,30 @@ module ActiveSearch
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
def to_indexable
|
24
|
+
{}.tap do |doc|
|
25
|
+
_locale = search_locale
|
26
|
+
|
27
|
+
search_fields.each do |field|
|
28
|
+
if content = send(field)
|
29
|
+
doc[field.to_s] = if content.is_a?(Hash) && content.has_key?(_locale)
|
30
|
+
ActiveSearch.strip_tags(content[_locale])
|
31
|
+
else
|
32
|
+
ActiveSearch.strip_tags(content)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
23
39
|
protected
|
40
|
+
|
24
41
|
def reindex
|
25
|
-
ActiveSearch::Mongoid::
|
42
|
+
ActiveSearch::Mongoid::Index.reindex(self, self.search_fields, self.search_options)
|
26
43
|
end
|
27
44
|
|
28
45
|
def deindex
|
29
|
-
ActiveSearch::Mongoid::
|
46
|
+
ActiveSearch::Mongoid::Index.deindex(self)
|
30
47
|
end
|
31
48
|
end
|
32
49
|
end
|
data/lib/activesearch/result.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'action_view'
|
2
2
|
require 'active_support/core_ext'
|
3
|
+
require 'active_support/core_ext/hash/slice'
|
3
4
|
|
4
5
|
module ActiveSearch
|
5
6
|
class Result < Hash
|
@@ -9,16 +10,22 @@ module ActiveSearch
|
|
9
10
|
include ActionView::Helpers::TextHelper
|
10
11
|
|
11
12
|
def initialize(result, text, options = {})
|
13
|
+
locale = (options[:locale] || I18n.locale).to_s
|
14
|
+
|
12
15
|
@text = text
|
13
16
|
result.to_hash.each do |k,v|
|
14
|
-
unless v.nil?
|
15
|
-
self[k.to_s] = v.respond_to?(:has_key?) && v.has_key?(
|
17
|
+
unless v.nil?
|
18
|
+
self[k.to_s] = v.respond_to?(:has_key?) && v.has_key?(locale) ? v[locale] : v
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
22
|
self.build_highlighted_fields(options[:radius])
|
20
23
|
end
|
21
24
|
|
25
|
+
def slice(*keys)
|
26
|
+
::Hash.new.update(self).slice(*keys)
|
27
|
+
end
|
28
|
+
|
22
29
|
protected
|
23
30
|
|
24
31
|
def build_highlighted_fields(radius = nil)
|
data/lib/activesearch/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'ActiveSearch::Algolia' do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
SetupEngine.setup(:algolia)
|
8
|
+
|
9
|
+
# can not use the rspec let method
|
10
|
+
@model = AlgoliaModel
|
11
|
+
@another_model = AnotherAlgoliaModel
|
12
|
+
end
|
13
|
+
|
14
|
+
include_examples 'an engine'
|
15
|
+
|
16
|
+
context 'retry on errors' do
|
17
|
+
|
18
|
+
before do
|
19
|
+
times_called = 0
|
20
|
+
@instance = AlgoliaModel.new(title: 'Example')
|
21
|
+
ActiveSearch::Algolia::Client.should_receive(:put).exactly(3).times.and_return do
|
22
|
+
times_called += 1
|
23
|
+
raise Errno::ECONNRESET if times_called <= 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { -> { @instance.save } }
|
28
|
+
|
29
|
+
it { should_not raise_error }
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -1,64 +1,64 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ActiveSearch::Base do
|
4
4
|
before do
|
5
5
|
@klass = Class.new do
|
6
6
|
include ActiveSearch::Base
|
7
|
-
|
7
|
+
|
8
8
|
def self.after_save(*args); end
|
9
9
|
def self.after_destroy(*args); end
|
10
|
-
|
10
|
+
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
context "search_by" do
|
15
15
|
let(:call_search_by) do
|
16
16
|
@klass.class_eval do
|
17
17
|
search_by [:field], if: :something_happens, unless: :its_friday
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
it "should rely on after_save and after_destroy callbacks passing conditions" do
|
22
22
|
@klass.should_receive(:after_save).with(:reindex, if: :something_happens, unless: :its_friday)
|
23
23
|
@klass.should_receive(:after_destroy).with(:deindex, if: :something_happens, unless: :its_friday)
|
24
24
|
call_search_by
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "should store the parameters in search_parameters" do
|
28
28
|
call_search_by
|
29
29
|
@klass.send(:search_parameters).should == [:field]
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
context "utility methods with options" do
|
34
34
|
before do
|
35
35
|
@klass.stub(:search_parameters).and_return([:field, store: [:another_field]])
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
it "search_options should return the hash at the end of the parameters" do
|
39
39
|
@klass.new.search_options.should == {store: [:another_field]}
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
it "search_fields should return all parameters except the options" do
|
43
43
|
@klass.new.search_fields.should == [:field]
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
context "search_by with virtual parameters" do
|
48
48
|
before do
|
49
49
|
@klass.class_eval do
|
50
50
|
def options_for_search
|
51
51
|
[@field]
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def initialize(field)
|
55
55
|
@field = field
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
search_by :options_for_search
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
it "should work" do
|
63
63
|
@klass.new(:first).send(:search_parameters).should == [:first]
|
64
64
|
@klass.new(:second).send(:search_parameters).should == [:second]
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'ActiveSearch::Mongoid' do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
SetupEngine.setup(:mongoid)
|
8
|
+
|
9
|
+
# can not use the rspec let method
|
10
|
+
@model = MongoidModel
|
11
|
+
@another_model = AnotherMongoidModel
|
12
|
+
end
|
13
|
+
|
14
|
+
include_examples 'an engine'
|
15
|
+
|
16
|
+
describe 'localized content' do
|
17
|
+
|
18
|
+
before(:all) do
|
19
|
+
@localized = LocalizedMongoidModel.create!(title: "<strong>English</strong> English")
|
20
|
+
I18n.with_locale(:es) do
|
21
|
+
@localized.title = "Español Español"
|
22
|
+
@localized.save!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to find by different locales" do
|
27
|
+
ActiveSearch.search("english").first["title"].should == "English English"
|
28
|
+
I18n.with_locale(:es) do
|
29
|
+
ActiveSearch.search("español").first["title"].should == "Español Español"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "finds by a different locale" do
|
34
|
+
ActiveSearch.search("español", {}, { locale: 'es'}).first["title"].should == "Español Español"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should store content with tags stripped" do
|
38
|
+
index = ActiveSearch::Mongoid::Index.where(original_type: "LocalizedMongoidModel", original_id: @localized.id, locale: 'en')
|
39
|
+
index.first.content.should == ["English English"]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "handles empty translations" do
|
43
|
+
lambda { LocalizedMongoidModel.create!(title: nil, not_localized: "example") }.should_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it "handles empty fields" do
|
47
|
+
lambda { LocalizedMongoidModel.create!(title: "Example", not_localized: nil) }.should_not raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it "handles nil values in arrays" do
|
51
|
+
lambda { LocalizedMongoidModel.create!(title: "Example", not_localized: "example", array: [nil]) }.should_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/spec/models/algolia.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
require 'activesearch/algolia'
|
2
|
-
|
3
1
|
class AlgoliaModel < ActiveMimic
|
4
2
|
include ActiveSearch::Algolia
|
5
|
-
|
3
|
+
|
6
4
|
attribute :title
|
7
5
|
attribute :text
|
8
6
|
attribute :junk
|
@@ -10,19 +8,19 @@ class AlgoliaModel < ActiveMimic
|
|
10
8
|
attribute :scope_id, type: Integer
|
11
9
|
attribute :tags, type: Array
|
12
10
|
localized_attribute :color
|
13
|
-
|
11
|
+
|
14
12
|
search_by [:title, :text, :tags, :color, store: [:title, :junk, :scope_id]], if: lambda { !self.special }
|
15
13
|
|
16
14
|
end
|
17
15
|
|
18
16
|
class AnotherAlgoliaModel < ActiveMimic
|
19
17
|
include ActiveSearch::Algolia
|
20
|
-
|
18
|
+
|
21
19
|
attribute :title, type: String
|
22
20
|
attribute :scope_id, type: Integer
|
23
21
|
localized_attribute :color
|
24
22
|
search_by [:title, store: [:title, :virtual, :scope_id, :color]]
|
25
|
-
|
23
|
+
|
26
24
|
def virtual
|
27
25
|
"virtual"
|
28
26
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
require 'activesearch/elastic_search'
|
2
|
-
|
3
1
|
module ElasticSearchRefresh
|
4
|
-
|
2
|
+
|
5
3
|
def save
|
6
4
|
super.tap { Tire.index('_all') { refresh }}
|
7
5
|
end
|
8
|
-
|
6
|
+
|
9
7
|
def destroy
|
10
8
|
super.tap { Tire.index('_all') { refresh }}
|
11
9
|
end
|
@@ -14,13 +12,12 @@ end
|
|
14
12
|
class ElasticSearchModel < ActiveMimic
|
15
13
|
include ActiveSearch::ElasticSearch
|
16
14
|
include ElasticSearchRefresh
|
17
|
-
|
15
|
+
|
18
16
|
attribute :title
|
19
|
-
attribute :text
|
20
17
|
attribute :junk
|
21
18
|
attribute :special, default: false
|
22
19
|
attribute :tags, type: Array
|
23
|
-
|
20
|
+
|
24
21
|
search_by [:title, :text, :tags, store: [:title, :junk]], if: lambda { !self.special }
|
25
22
|
|
26
23
|
end
|
@@ -28,10 +25,10 @@ end
|
|
28
25
|
class AnotherElasticSearchModel < ActiveMimic
|
29
26
|
include ActiveSearch::ElasticSearch
|
30
27
|
include ElasticSearchRefresh
|
31
|
-
|
28
|
+
|
32
29
|
attribute :title, type: String
|
33
30
|
search_by [:title, store: [:title, :virtual]]
|
34
|
-
|
31
|
+
|
35
32
|
def virtual
|
36
33
|
"virtual"
|
37
34
|
end
|