sunspot_association 0.0.2 → 0.1.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/Gemfile.lock +2 -3
- data/MIT-LICENSE +1 -1
- data/README.md +33 -43
- data/lib/sunspot_association/model.rb +107 -0
- data/lib/sunspot_association/searchable.rb +77 -0
- data/lib/sunspot_association/version.rb +1 -1
- data/lib/sunspot_association.rb +2 -106
- data/spec/sunspot_association/model_spec.rb +165 -0
- data/spec/sunspot_association/searchable_spec.rb +263 -0
- data/spec/sunspot_association_spec.rb +0 -161
- data/sunspot_association.gemspec +3 -3
- metadata +10 -4
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sunspot_association (0.0.
|
4
|
+
sunspot_association (0.0.2)
|
5
5
|
activerecord (~> 3.0)
|
6
|
-
|
6
|
+
sunspot_rails
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: http://rubygems.org/
|
@@ -85,7 +85,6 @@ GEM
|
|
85
85
|
sunspot_rails (1.3.3)
|
86
86
|
nokogiri
|
87
87
|
sunspot (= 1.3.3)
|
88
|
-
sunspot_solr (2.0.0)
|
89
88
|
sunspot_test (0.4.0)
|
90
89
|
sunspot_rails (>= 1.2.1)
|
91
90
|
terminal-table (1.4.5)
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,23 +1,39 @@
|
|
1
1
|
# sunspot_association [](http://badge.fury.io/rb/sunspot_association) [](http://travis-ci.org/Arjeno/sunspot_association) [](https://gemnasium.com/Arjeno/sunspot_association) [](https://coveralls.io/r/Arjeno/sunspot_association)
|
2
2
|
|
3
|
-
|
3
|
+
Automatic association (re)indexing for your searchable Sunspot models.
|
4
4
|
|
5
|
-
##
|
6
|
-
|
7
|
-
Add to your Gemfile:
|
5
|
+
## Pure magic
|
8
6
|
|
9
7
|
```ruby
|
10
|
-
|
8
|
+
class User < ActiveRecord::Base
|
9
|
+
belongs_to :company
|
10
|
+
searchable do
|
11
|
+
associate :text, :company, :name, :phone
|
12
|
+
end
|
13
|
+
end
|
11
14
|
```
|
12
15
|
|
13
|
-
|
16
|
+
## What it does
|
17
|
+
|
18
|
+
The above example will convert to:
|
14
19
|
|
15
20
|
```ruby
|
16
|
-
|
17
|
-
|
21
|
+
searchable do
|
22
|
+
text :company_name do; company.name end
|
23
|
+
text :company_phone do; company.phone end
|
18
24
|
end
|
19
25
|
```
|
20
26
|
|
27
|
+
It will also hook into `Company` and watch it for changes
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Add to your Gemfile:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
gem 'sunspot_association'
|
35
|
+
```
|
36
|
+
|
21
37
|
## Example
|
22
38
|
|
23
39
|
```ruby
|
@@ -25,50 +41,24 @@ class User < ActiveRecord::Base
|
|
25
41
|
belongs_to :company
|
26
42
|
|
27
43
|
searchable do
|
28
|
-
text :
|
29
|
-
|
30
|
-
end
|
44
|
+
associate :text, :company, :name, :phone
|
45
|
+
associate :string, :company, :address, :stored => true
|
31
46
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
text :company_name do; company.try(:name) end
|
47
|
+
# Converts to:
|
48
|
+
# => text :company_name do; company.name end
|
49
|
+
# => text :company_phone do; company.phone end
|
50
|
+
# => string :company_address, { :stored => true } do; company.address end
|
37
51
|
end
|
38
52
|
end
|
39
53
|
|
40
54
|
class Company < ActiveRecord::Base
|
41
|
-
has_many :orders
|
42
55
|
has_many :users
|
43
56
|
|
44
|
-
|
45
|
-
|
46
|
-
# Or only track changes for the name field
|
47
|
-
# => sunspot_associate :orders, :users, :fields => :name
|
57
|
+
# This configuration is automatically added by the searchable DSL
|
58
|
+
# => sunspot_associate :users, :fields => [:name, :phone, :address]
|
48
59
|
end
|
49
60
|
```
|
50
61
|
|
51
62
|
## License
|
52
63
|
|
53
|
-
|
54
|
-
|
55
|
-
MIT License
|
56
|
-
|
57
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
58
|
-
a copy of this software and associated documentation files (the
|
59
|
-
"Software"), to deal in the Software without restriction, including
|
60
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
61
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
62
|
-
permit persons to whom the Software is furnished to do so, subject to
|
63
|
-
the following conditions:
|
64
|
-
|
65
|
-
The above copyright notice and this permission notice shall be
|
66
|
-
included in all copies or substantial portions of the Software.
|
67
|
-
|
68
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
69
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
70
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
71
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
72
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
73
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
74
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
64
|
+
sunspot_association is distributed under the MIT License, copyright © 2013 Arjen Oosterkamp
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module SunspotAssociation
|
4
|
+
module Model
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
|
10
|
+
## Attributes
|
11
|
+
|
12
|
+
cattr_accessor :sunspot_association_configuration
|
13
|
+
|
14
|
+
after_create Proc.new { |o| o.reindex_sunspot_associations!(:create) }
|
15
|
+
after_update Proc.new { |o| o.reindex_sunspot_associations!(:update) }
|
16
|
+
after_destroy Proc.new { |o| o.reindex_sunspot_associations!(:destroy) }
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
|
22
|
+
def sunspot_associate?
|
23
|
+
self.sunspot_association_configuration != {}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Reindex associations when a model changes
|
27
|
+
#
|
28
|
+
# Options:
|
29
|
+
#
|
30
|
+
# :fields
|
31
|
+
# => Field(s) to watch for changes
|
32
|
+
#
|
33
|
+
# :on_create
|
34
|
+
# => Specifies if it should reindex associations when a record is created
|
35
|
+
#
|
36
|
+
# Examples:
|
37
|
+
#
|
38
|
+
# => sunspot_associate :orders, :fields => :name
|
39
|
+
# => sunspot_associate :orders, :users, :fields => [:name, :phone], :on_create => true
|
40
|
+
#
|
41
|
+
def sunspot_associate(*args)
|
42
|
+
options = args.extract_options!
|
43
|
+
fields = options.delete(:fields)
|
44
|
+
|
45
|
+
self.sunspot_association_configuration ||= {}
|
46
|
+
|
47
|
+
args.each do |object|
|
48
|
+
default = { :fields => [] }
|
49
|
+
config = self.sunspot_association_configuration[object] || default
|
50
|
+
|
51
|
+
# Fields
|
52
|
+
config[:fields] += Array(fields)
|
53
|
+
config[:fields].compact!
|
54
|
+
config[:fields].uniq!
|
55
|
+
|
56
|
+
config.merge!(options)
|
57
|
+
|
58
|
+
self.sunspot_association_configuration[object] = config
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def reset_sunspot_associations!
|
63
|
+
self.sunspot_association_configuration = {}
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# Main callback method, checks if it should reindex an association
|
69
|
+
def reindex_sunspot_associations!(event)
|
70
|
+
self.class.sunspot_association_configuration.each do |object, config|
|
71
|
+
case event
|
72
|
+
when :create
|
73
|
+
reindex_sunspot_association!(object) if config[:on_create]
|
74
|
+
when :update
|
75
|
+
reindex_sunspot_association!(object) if reindex_sunspot_association?(object)
|
76
|
+
when :destroy
|
77
|
+
reindex_sunspot_association!(object)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Checks if an association should be reindexed
|
83
|
+
# => reindex_sunspot_association?(:orders) => true
|
84
|
+
def reindex_sunspot_association?(object)
|
85
|
+
if (config = (self.class.sunspot_association_configuration || {})[object]).present?
|
86
|
+
if config[:fields].present?
|
87
|
+
return ! (changed & (config[:fields] || []).map(&:to_s)).empty?
|
88
|
+
else
|
89
|
+
return changed.any?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
# Reindexes an association using Sunspot.index
|
97
|
+
def reindex_sunspot_association!(object)
|
98
|
+
return false unless self.class.sunspot_associate?
|
99
|
+
return false unless self.respond_to?(object)
|
100
|
+
|
101
|
+
Sunspot.index self.send(object)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
ActiveRecord::Base.send(:include, SunspotAssociation::Model)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'sunspot/rails'
|
2
|
+
|
3
|
+
module SunspotAssociation
|
4
|
+
module Searchable
|
5
|
+
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# Index association fields
|
9
|
+
#
|
10
|
+
# Options:
|
11
|
+
#
|
12
|
+
# :inverse_name - see `setup_association_reindex`
|
13
|
+
#
|
14
|
+
# :index_on_change
|
15
|
+
# => Boolean or array
|
16
|
+
# => Defaults to `fields`
|
17
|
+
# => Set to false to disable automatic reindexing
|
18
|
+
# => Set to true to reindex for every update
|
19
|
+
# => Pass array of fields to specifically watch
|
20
|
+
#
|
21
|
+
# Examples:
|
22
|
+
#
|
23
|
+
# => associate :text, :company, :name
|
24
|
+
# => associate :text, :company, :name, :phone
|
25
|
+
# => associate :text, :company, :name, :phone, :inverse_name => :company_users
|
26
|
+
#
|
27
|
+
def associate(type, association_name, *fields)
|
28
|
+
options = fields.extract_options!
|
29
|
+
|
30
|
+
inverse_name = options.delete(:inverse_name)
|
31
|
+
index_on_change = options.delete(:index_on_change)
|
32
|
+
|
33
|
+
fields.each do |field|
|
34
|
+
name = [association_name, field].join('_')
|
35
|
+
self.send(type, name, options) do
|
36
|
+
self.send(association_name).send(field)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
unless index_on_change == false
|
41
|
+
fields_to_watch = fields
|
42
|
+
|
43
|
+
if index_on_change.is_a?(Array)
|
44
|
+
fields_to_watch = index_on_change
|
45
|
+
elsif index_on_change == true
|
46
|
+
fields_to_watch = []
|
47
|
+
end
|
48
|
+
|
49
|
+
setup_association_reindex association_name, fields_to_watch, { :inverse_name => inverse_name }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set up automatic reindexing using `sunspot_associate`
|
54
|
+
#
|
55
|
+
# Options:
|
56
|
+
#
|
57
|
+
# :inverse_name
|
58
|
+
# => Name of inverse association to use, for example :company_users
|
59
|
+
#
|
60
|
+
# Examples:
|
61
|
+
#
|
62
|
+
# => setup_association_reindex :company, [:name]
|
63
|
+
# => setup_association_reindex :company, [:name], :inverse_name => :company_users
|
64
|
+
#
|
65
|
+
def setup_association_reindex(association_name, fields, options={})
|
66
|
+
searchable_class = @setup.clazz
|
67
|
+
association = searchable_class.reflect_on_association(association_name)
|
68
|
+
association_class = association.klass
|
69
|
+
inverse_name = options[:inverse_name] || searchable_class.name.pluralize.downcase.to_sym
|
70
|
+
|
71
|
+
association_class.sunspot_associate inverse_name, :fields => fields
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Sunspot::DSL::Fields.send(:include, SunspotAssociation::Searchable)
|
data/lib/sunspot_association.rb
CHANGED
@@ -1,110 +1,6 @@
|
|
1
|
-
require 'active_record'
|
2
1
|
require 'sunspot_association/version'
|
2
|
+
require 'sunspot_association/model'
|
3
|
+
require 'sunspot_association/searchable'
|
3
4
|
|
4
5
|
module SunspotAssociation
|
5
|
-
module Model
|
6
|
-
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
included do
|
10
|
-
|
11
|
-
## Attributes
|
12
|
-
|
13
|
-
cattr_accessor :sunspot_association_configuration
|
14
|
-
|
15
|
-
## Callbacks
|
16
|
-
|
17
|
-
after_create Proc.new { |o| o.reindex_sunspot_associations!(:create) }
|
18
|
-
after_update Proc.new { |o| o.reindex_sunspot_associations!(:update) }
|
19
|
-
after_destroy Proc.new { |o| o.reindex_sunspot_associations!(:destroy) }
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
module ClassMethods
|
24
|
-
|
25
|
-
def sunspot_associate?
|
26
|
-
self.sunspot_association_configuration != {}
|
27
|
-
end
|
28
|
-
|
29
|
-
# Reindex associations when a model changes
|
30
|
-
#
|
31
|
-
# Options:
|
32
|
-
#
|
33
|
-
# :fields
|
34
|
-
# => Field(s) to watch for changes
|
35
|
-
#
|
36
|
-
# :on_create
|
37
|
-
# => Specifies if it should reindex associations when a record is created
|
38
|
-
#
|
39
|
-
# Examples:
|
40
|
-
#
|
41
|
-
# => sunspot_associate :orders, :fields => :name
|
42
|
-
# => sunspot_associate :orders, :users, :fields => [:name, :phone], :on_create => true
|
43
|
-
#
|
44
|
-
def sunspot_associate(*args)
|
45
|
-
options = args.extract_options!
|
46
|
-
fields = options.delete(:fields)
|
47
|
-
|
48
|
-
self.sunspot_association_configuration ||= {}
|
49
|
-
|
50
|
-
args.each do |object|
|
51
|
-
default = { :fields => [] }
|
52
|
-
config = self.sunspot_association_configuration[object] || default
|
53
|
-
|
54
|
-
# Fields
|
55
|
-
config[:fields] += Array(fields)
|
56
|
-
config[:fields].compact!
|
57
|
-
config[:fields].uniq!
|
58
|
-
|
59
|
-
config.merge!(options)
|
60
|
-
|
61
|
-
self.sunspot_association_configuration[object] = config
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def reset_sunspot_associations!
|
66
|
-
self.sunspot_association_configuration = {}
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
# Main callback method, checks if it should reindex an association
|
72
|
-
def reindex_sunspot_associations!(event)
|
73
|
-
self.class.sunspot_association_configuration.each do |object, config|
|
74
|
-
case event
|
75
|
-
when :create
|
76
|
-
reindex_sunspot_association!(object) if config[:on_create]
|
77
|
-
when :update
|
78
|
-
reindex_sunspot_association!(object) if reindex_sunspot_association?(object)
|
79
|
-
when :destroy
|
80
|
-
reindex_sunspot_association!(object)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Checks if an association should be reindexed
|
86
|
-
# => reindex_sunspot_association?(:orders) => true
|
87
|
-
def reindex_sunspot_association?(object)
|
88
|
-
if (config = (self.class.sunspot_association_configuration || {})[object]).present?
|
89
|
-
if config[:fields].present?
|
90
|
-
return ! (changed & (config[:fields] || []).map(&:to_s)).empty?
|
91
|
-
else
|
92
|
-
return changed.any?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
false
|
97
|
-
end
|
98
|
-
|
99
|
-
# Reindexes an association using Sunspot.index
|
100
|
-
def reindex_sunspot_association!(object)
|
101
|
-
return false unless self.class.sunspot_associate?
|
102
|
-
return false unless self.respond_to?(object)
|
103
|
-
|
104
|
-
Sunspot.index self.send(object)
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
6
|
end
|
109
|
-
|
110
|
-
ActiveRecord::Base.send(:include, SunspotAssociation::Model)
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SunspotAssociation::Model do
|
4
|
+
|
5
|
+
with_model :User do
|
6
|
+
table do |t|
|
7
|
+
t.belongs_to :company
|
8
|
+
t.string :name
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
model do
|
13
|
+
belongs_to :company
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
with_model :Order do
|
18
|
+
table do |t|
|
19
|
+
t.belongs_to :company
|
20
|
+
t.string :number
|
21
|
+
t.timestamps
|
22
|
+
end
|
23
|
+
|
24
|
+
model do
|
25
|
+
belongs_to :company
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
with_model :Company do
|
30
|
+
table do |t|
|
31
|
+
t.string :name
|
32
|
+
t.string :number
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
|
36
|
+
model do
|
37
|
+
has_many :orders
|
38
|
+
has_many :users
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:company) { Company.create({ :name => 'Company name', :number => '1' }) }
|
43
|
+
let(:order) { Order.create({ :number => '1', :company => company }) }
|
44
|
+
let(:user) { User.create({ :name => 'John Doe', :company => company }) }
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
Company.sunspot_associate :orders, :fields => :name
|
48
|
+
Company.sunspot_associate :users, :on_create => true
|
49
|
+
end
|
50
|
+
|
51
|
+
after(:each) do
|
52
|
+
Company.reset_sunspot_associations!
|
53
|
+
end
|
54
|
+
|
55
|
+
describe :sunspot_association_configuration do
|
56
|
+
|
57
|
+
it do
|
58
|
+
Company.sunspot_association_configuration.should == {
|
59
|
+
:orders => { :fields => [:name] },
|
60
|
+
:users => { :fields => [], :on_create => true }
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with multiple objects' do
|
65
|
+
|
66
|
+
before(:each) do
|
67
|
+
Company.sunspot_associate :orders, :users, :fields => :name, :on_create => true
|
68
|
+
end
|
69
|
+
|
70
|
+
it do
|
71
|
+
Company.sunspot_association_configuration.should == {
|
72
|
+
:orders => { :fields => [:name], :on_create => true },
|
73
|
+
:users => { :fields => [:name], :on_create => true },
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
describe :reindex_sunspot_association? do
|
82
|
+
|
83
|
+
subject { company }
|
84
|
+
|
85
|
+
context 'without changes' do
|
86
|
+
|
87
|
+
it { company.reindex_sunspot_association?(:orders).should be_false }
|
88
|
+
it { company.reindex_sunspot_association?(:users).should be_false }
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with changes' do
|
93
|
+
|
94
|
+
before(:each) { company.name = 'Name change' }
|
95
|
+
|
96
|
+
it { company.reindex_sunspot_association?(:orders).should be_true }
|
97
|
+
it { company.reindex_sunspot_association?(:users).should be_true }
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with any change' do
|
102
|
+
|
103
|
+
before(:each) { company.number = '5' }
|
104
|
+
|
105
|
+
it { company.reindex_sunspot_association?(:orders).should be_false }
|
106
|
+
it { company.reindex_sunspot_association?(:users).should be_true }
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
describe :callbacks do
|
113
|
+
|
114
|
+
context :after_create do
|
115
|
+
|
116
|
+
let(:company) { Company.new }
|
117
|
+
after(:each) { company.save }
|
118
|
+
|
119
|
+
it do
|
120
|
+
company.should_not_receive(:reindex_sunspot_association!).with(:orders)
|
121
|
+
company.should_receive(:reindex_sunspot_association!).with(:users)
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
context :after_update do
|
127
|
+
|
128
|
+
context 'with tracked change' do
|
129
|
+
|
130
|
+
after(:each) { company.update_attributes({ :name => 'name change' }) }
|
131
|
+
|
132
|
+
it do
|
133
|
+
company.should_receive(:reindex_sunspot_association!).with(:orders)
|
134
|
+
company.should_receive(:reindex_sunspot_association!).with(:users)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with untracked change' do
|
140
|
+
|
141
|
+
after(:each) { company.update_attributes({ :number => '5' }) }
|
142
|
+
|
143
|
+
it do
|
144
|
+
company.should_not_receive(:reindex_sunspot_association!).with(:orders)
|
145
|
+
company.should_receive(:reindex_sunspot_association!).with(:users)
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
context :after_destroy do
|
153
|
+
|
154
|
+
after(:each) { company.destroy }
|
155
|
+
|
156
|
+
it do
|
157
|
+
company.should_receive(:reindex_sunspot_association!).with(:orders)
|
158
|
+
company.should_receive(:reindex_sunspot_association!).with(:users)
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SunspotAssociation::Searchable do
|
4
|
+
|
5
|
+
## Shared examples
|
6
|
+
|
7
|
+
shared_examples_for 'a searchable field' do |searchable_field, type, stored|
|
8
|
+
stored ||= false
|
9
|
+
|
10
|
+
let(:field) { fetch_fields(searchable_field, model) }
|
11
|
+
let(:data) { field.build }
|
12
|
+
|
13
|
+
subject { field }
|
14
|
+
|
15
|
+
it { should be_present }
|
16
|
+
it { data.instance_variable_get(:@stored).should == stored }
|
17
|
+
it { data.type.class.should == type } if type
|
18
|
+
end
|
19
|
+
|
20
|
+
## Methods
|
21
|
+
|
22
|
+
def fetch_fields(name, model)
|
23
|
+
fields = Sunspot::Setup.for(model).field_factories
|
24
|
+
fields += Sunspot::Setup.for(model).text_field_factories
|
25
|
+
fields += Sunspot::Setup.for(model).dynamic_field_factories
|
26
|
+
|
27
|
+
fields.flatten!
|
28
|
+
|
29
|
+
found_fields = fields.collect do |f|
|
30
|
+
f if f.name == name
|
31
|
+
end.compact
|
32
|
+
|
33
|
+
found_fields.count > 1 ? found_fields : found_fields.first
|
34
|
+
end
|
35
|
+
|
36
|
+
## Models
|
37
|
+
|
38
|
+
with_model :User do
|
39
|
+
table do |t|
|
40
|
+
t.belongs_to :company
|
41
|
+
t.string :name
|
42
|
+
t.timestamps
|
43
|
+
end
|
44
|
+
|
45
|
+
model do
|
46
|
+
include Sunspot::Rails::Searchable
|
47
|
+
belongs_to :company
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
with_model :Company do
|
52
|
+
table do |t|
|
53
|
+
t.string :name
|
54
|
+
t.string :phone
|
55
|
+
t.timestamps
|
56
|
+
end
|
57
|
+
|
58
|
+
model do
|
59
|
+
has_many :users
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe :associate do
|
64
|
+
|
65
|
+
describe :setup_association_reindex do
|
66
|
+
|
67
|
+
after(:each) do
|
68
|
+
Company.reset_sunspot_associations!
|
69
|
+
end
|
70
|
+
|
71
|
+
subject { Company.sunspot_association_configuration }
|
72
|
+
|
73
|
+
describe 'default' do
|
74
|
+
|
75
|
+
before(:each) do
|
76
|
+
User.searchable do
|
77
|
+
associate :text, :company, :name
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it { should == { :users => { :fields => [:name] } } }
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe :inverse_name do
|
86
|
+
|
87
|
+
before(:each) do
|
88
|
+
User.searchable do
|
89
|
+
associate :text, :company, :name, :inverse_name => :company_users
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it { should == { :company_users => { :fields => [:name] } } }
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
describe :index_on_change do
|
98
|
+
|
99
|
+
context 'with true' do
|
100
|
+
|
101
|
+
before(:each) do
|
102
|
+
User.searchable do
|
103
|
+
associate :text, :company, :name, :index_on_change => true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it { should == { :users => { :fields => [] } } }
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'with false' do
|
112
|
+
|
113
|
+
before(:each) do
|
114
|
+
User.searchable do
|
115
|
+
associate :text, :company, :name, :index_on_change => false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it { should == {} }
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'with array' do
|
124
|
+
|
125
|
+
before(:each) do
|
126
|
+
User.searchable do
|
127
|
+
associate :text, :company, :pretty_address, :index_on_change => [:address]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it { should == { :users => { :fields => [:address] } } }
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
describe :sunspot_settings do
|
140
|
+
|
141
|
+
let(:model) { User }
|
142
|
+
|
143
|
+
describe :text do
|
144
|
+
|
145
|
+
before(:each) do
|
146
|
+
User.searchable do
|
147
|
+
associate :text, :company, :name
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::TextType
|
152
|
+
|
153
|
+
it do
|
154
|
+
Company.sunspot_association_configuration.should == {
|
155
|
+
:users => { :fields => [:name] }
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'with multiple' do
|
160
|
+
|
161
|
+
describe 'in one call' do
|
162
|
+
|
163
|
+
before(:each) do
|
164
|
+
User.searchable do
|
165
|
+
associate :text, :company, :name, :phone
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::TextType
|
170
|
+
it_should_behave_like 'a searchable field', :company_phone, Sunspot::Type::TextType
|
171
|
+
|
172
|
+
it do
|
173
|
+
Company.sunspot_association_configuration.should == {
|
174
|
+
:users => { :fields => [:name, :phone] }
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'in multiple calls' do
|
181
|
+
|
182
|
+
before(:each) do
|
183
|
+
User.searchable do
|
184
|
+
associate :text, :company, :name
|
185
|
+
associate :text, :company, :phone
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::TextType
|
190
|
+
it_should_behave_like 'a searchable field', :company_phone, Sunspot::Type::TextType
|
191
|
+
|
192
|
+
it do
|
193
|
+
Company.sunspot_association_configuration.should == {
|
194
|
+
:users => { :fields => [:name, :phone] }
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
describe :string do
|
205
|
+
|
206
|
+
before(:each) do
|
207
|
+
User.searchable do
|
208
|
+
associate :string, :company, :name
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::StringType
|
213
|
+
|
214
|
+
context 'with stored' do
|
215
|
+
|
216
|
+
before(:each) do
|
217
|
+
User.searchable do
|
218
|
+
associate :string, :company, :name, :stored => true
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::StringType, true
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
context 'with multiple' do
|
227
|
+
|
228
|
+
describe 'in one call' do
|
229
|
+
|
230
|
+
before(:each) do
|
231
|
+
User.searchable do
|
232
|
+
associate :string, :company, :name, :phone
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::StringType
|
237
|
+
it_should_behave_like 'a searchable field', :company_phone, Sunspot::Type::StringType
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
describe 'in multiple calls' do
|
242
|
+
|
243
|
+
before(:each) do
|
244
|
+
User.searchable do
|
245
|
+
associate :string, :company, :name
|
246
|
+
associate :string, :company, :phone
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
it_should_behave_like 'a searchable field', :company_name, Sunspot::Type::StringType
|
251
|
+
it_should_behave_like 'a searchable field', :company_phone, Sunspot::Type::StringType
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
@@ -1,165 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe SunspotAssociation do
|
4
|
-
|
5
|
-
with_model :User do
|
6
|
-
table do |t|
|
7
|
-
t.belongs_to :company
|
8
|
-
t.string :name
|
9
|
-
t.timestamps
|
10
|
-
end
|
11
|
-
|
12
|
-
model do
|
13
|
-
belongs_to :company
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
with_model :Order do
|
18
|
-
table do |t|
|
19
|
-
t.belongs_to :company
|
20
|
-
t.string :number
|
21
|
-
t.timestamps
|
22
|
-
end
|
23
|
-
|
24
|
-
model do
|
25
|
-
belongs_to :company
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
with_model :Company do
|
30
|
-
table do |t|
|
31
|
-
t.string :name
|
32
|
-
t.string :number
|
33
|
-
t.timestamps
|
34
|
-
end
|
35
|
-
|
36
|
-
model do
|
37
|
-
has_many :orders
|
38
|
-
has_many :users
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
let(:company) { Company.create({ :name => 'Company name', :number => '1' }) }
|
43
|
-
let(:order) { Order.create({ :number => '1', :company => company }) }
|
44
|
-
let(:user) { User.create({ :name => 'John Doe', :company => company }) }
|
45
|
-
|
46
|
-
before(:each) do
|
47
|
-
Company.sunspot_associate :orders, :fields => :name
|
48
|
-
Company.sunspot_associate :users, :on_create => true
|
49
|
-
end
|
50
|
-
|
51
|
-
after(:each) do
|
52
|
-
Company.reset_sunspot_associations!
|
53
|
-
end
|
54
|
-
|
55
|
-
describe :sunspot_association_configuration do
|
56
|
-
|
57
|
-
it do
|
58
|
-
Company.sunspot_association_configuration.should == {
|
59
|
-
:orders => { :fields => [:name] },
|
60
|
-
:users => { :fields => [], :on_create => true }
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'with multiple objects' do
|
65
|
-
|
66
|
-
before(:each) do
|
67
|
-
Company.sunspot_associate :orders, :users, :fields => :name, :on_create => true
|
68
|
-
end
|
69
|
-
|
70
|
-
it do
|
71
|
-
Company.sunspot_association_configuration.should == {
|
72
|
-
:orders => { :fields => [:name], :on_create => true },
|
73
|
-
:users => { :fields => [:name], :on_create => true },
|
74
|
-
}
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
describe :reindex_sunspot_association? do
|
82
|
-
|
83
|
-
subject { company }
|
84
|
-
|
85
|
-
context 'without changes' do
|
86
|
-
|
87
|
-
it { company.reindex_sunspot_association?(:orders).should be_false }
|
88
|
-
it { company.reindex_sunspot_association?(:users).should be_false }
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
context 'with changes' do
|
93
|
-
|
94
|
-
before(:each) { company.name = 'Name change' }
|
95
|
-
|
96
|
-
it { company.reindex_sunspot_association?(:orders).should be_true }
|
97
|
-
it { company.reindex_sunspot_association?(:users).should be_true }
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
context 'with any change' do
|
102
|
-
|
103
|
-
before(:each) { company.number = '5' }
|
104
|
-
|
105
|
-
it { company.reindex_sunspot_association?(:orders).should be_false }
|
106
|
-
it { company.reindex_sunspot_association?(:users).should be_true }
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
|
-
describe :callbacks do
|
113
|
-
|
114
|
-
context :after_create do
|
115
|
-
|
116
|
-
let(:company) { Company.new }
|
117
|
-
after(:each) { company.save }
|
118
|
-
|
119
|
-
it do
|
120
|
-
company.should_not_receive(:reindex_sunspot_association!).with(:orders)
|
121
|
-
company.should_receive(:reindex_sunspot_association!).with(:users)
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
context :after_update do
|
127
|
-
|
128
|
-
context 'with tracked change' do
|
129
|
-
|
130
|
-
after(:each) { company.update_attributes({ :name => 'name change' }) }
|
131
|
-
|
132
|
-
it do
|
133
|
-
company.should_receive(:reindex_sunspot_association!).with(:orders)
|
134
|
-
company.should_receive(:reindex_sunspot_association!).with(:users)
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
context 'with untracked change' do
|
140
|
-
|
141
|
-
after(:each) { company.update_attributes({ :number => '5' }) }
|
142
|
-
|
143
|
-
it do
|
144
|
-
company.should_not_receive(:reindex_sunspot_association!).with(:orders)
|
145
|
-
company.should_receive(:reindex_sunspot_association!).with(:users)
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|
149
|
-
|
150
|
-
end
|
151
|
-
|
152
|
-
context :after_destroy do
|
153
|
-
|
154
|
-
after(:each) { company.destroy }
|
155
|
-
|
156
|
-
it do
|
157
|
-
company.should_receive(:reindex_sunspot_association!).with(:orders)
|
158
|
-
company.should_receive(:reindex_sunspot_association!).with(:users)
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
4
|
end
|
data/sunspot_association.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.authors = ["Arjen Oosterkamp"]
|
11
11
|
s.email = ["mail@arjen.me"]
|
12
12
|
s.homepage = ""
|
13
|
-
s.summary = %q{
|
14
|
-
s.description = %q{
|
13
|
+
s.summary = %q{Automatic association (re)indexing for your searchable Sunspot models.}
|
14
|
+
s.description = %q{Automatic association (re)indexing for your searchable Sunspot models.}
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -26,5 +26,5 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency "coveralls"
|
27
27
|
|
28
28
|
s.add_dependency "activerecord", "~> 3.0"
|
29
|
-
s.add_dependency "
|
29
|
+
s.add_dependency "sunspot_rails"
|
30
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunspot_association
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -108,7 +108,7 @@ dependencies:
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '3.0'
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
111
|
+
name: sunspot_rails
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
113
113
|
none: false
|
114
114
|
requirements:
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
|
-
description:
|
126
|
+
description: Automatic association (re)indexing for your searchable Sunspot models.
|
127
127
|
email:
|
128
128
|
- mail@arjen.me
|
129
129
|
executables: []
|
@@ -139,8 +139,12 @@ files:
|
|
139
139
|
- README.md
|
140
140
|
- Rakefile
|
141
141
|
- lib/sunspot_association.rb
|
142
|
+
- lib/sunspot_association/model.rb
|
143
|
+
- lib/sunspot_association/searchable.rb
|
142
144
|
- lib/sunspot_association/version.rb
|
143
145
|
- spec/spec_helper.rb
|
146
|
+
- spec/sunspot_association/model_spec.rb
|
147
|
+
- spec/sunspot_association/searchable_spec.rb
|
144
148
|
- spec/sunspot_association_spec.rb
|
145
149
|
- sunspot_association.gemspec
|
146
150
|
homepage: ''
|
@@ -166,8 +170,10 @@ rubyforge_project:
|
|
166
170
|
rubygems_version: 1.8.24
|
167
171
|
signing_key:
|
168
172
|
specification_version: 3
|
169
|
-
summary:
|
173
|
+
summary: Automatic association (re)indexing for your searchable Sunspot models.
|
170
174
|
test_files:
|
171
175
|
- spec/spec_helper.rb
|
176
|
+
- spec/sunspot_association/model_spec.rb
|
177
|
+
- spec/sunspot_association/searchable_spec.rb
|
172
178
|
- spec/sunspot_association_spec.rb
|
173
179
|
has_rdoc:
|