sunspot_rails 0.10.9 → 0.11.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/History.txt +15 -0
- data/README.rdoc +44 -30
- data/Rakefile +9 -1
- data/TODO +15 -0
- data/VERSION.yml +2 -2
- data/dev_tasks/gemspec.rake +10 -3
- data/generators/sunspot/sunspot_generator.rb +9 -0
- data/generators/sunspot/templates/sunspot.yml +18 -0
- data/lib/sunspot/rails.rb +9 -0
- data/lib/sunspot/rails/adapters.rb +27 -2
- data/lib/sunspot/rails/configuration.rb +140 -6
- data/lib/sunspot/rails/request_lifecycle.rb +5 -1
- data/lib/sunspot/rails/searchable.rb +15 -11
- data/lib/sunspot/rails/server.rb +229 -0
- data/lib/sunspot/rails/session_proxy.rb +62 -0
- data/lib/sunspot/rails/tasks.rb +17 -35
- data/lib/sunspot/rails/util.rb +20 -0
- data/lib/sunspot/spec/extension.rb +45 -0
- data/rails/init.rb +1 -4
- data/spec/configuration_spec.rb +70 -21
- data/spec/mock_app/app/models/author.rb +8 -0
- data/spec/mock_app/app/models/post_with_auto.rb +1 -1
- data/spec/mock_app/config/database.yml +1 -1
- data/spec/mock_app/config/environment.rb +2 -1
- data/spec/mock_app/config/sunspot.yml +5 -0
- data/spec/mock_app/db/schema.rb +20 -0
- data/spec/mock_app/db/test.db +1 -0
- data/spec/model_lifecycle_spec.rb +17 -2
- data/spec/model_spec.rb +38 -2
- data/spec/request_lifecycle_spec.rb +23 -1
- data/spec/schema.rb +6 -0
- data/spec/server_spec.rb +124 -0
- data/spec/session_spec.rb +24 -0
- data/spec/spec_helper.rb +23 -4
- data/spec/sunspot_mocking_spec.rb +22 -0
- data/spec/util_spec.rb +15 -0
- metadata +36 -15
@@ -9,7 +9,11 @@ module Sunspot #:nodoc:
|
|
9
9
|
class <<self
|
10
10
|
def included(base) #:nodoc:
|
11
11
|
base.after_filter do
|
12
|
-
|
12
|
+
if Sunspot::Rails.configuration.auto_commit_after_request?
|
13
|
+
Sunspot.commit_if_dirty
|
14
|
+
elsif Sunspot::Rails.configuration.auto_commit_after_delete_request?
|
15
|
+
Sunspot.commit_if_delete_dirty
|
16
|
+
end
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -34,6 +34,9 @@ module Sunspot #:nodoc:
|
|
34
34
|
# Automatically remove models from the Solr index when they are
|
35
35
|
# destroyed. <b>Setting this option to +false+ is not recommended
|
36
36
|
# </b>(see the README).
|
37
|
+
# :ignore_attribute_changes_of<Array>::
|
38
|
+
# Define attributes, that should not trigger a reindex of that
|
39
|
+
# object. Usual suspects are update_at or counters.
|
37
40
|
#
|
38
41
|
# ==== Example
|
39
42
|
#
|
@@ -54,10 +57,12 @@ module Sunspot #:nodoc:
|
|
54
57
|
unless searchable?
|
55
58
|
extend ClassMethods
|
56
59
|
include InstanceMethods
|
57
|
-
|
60
|
+
|
61
|
+
Sunspot::Rails::Util.sunspot_options[self.to_s.underscore.to_sym] = options
|
62
|
+
|
58
63
|
unless options[:auto_index] == false
|
59
64
|
after_save do |searchable|
|
60
|
-
searchable.index
|
65
|
+
searchable.index if Sunspot::Rails::Util.index_relevant_attribute_changed?( searchable )
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|
@@ -136,7 +141,7 @@ module Sunspot #:nodoc:
|
|
136
141
|
# XXX Sunspot should implement remove_all!()
|
137
142
|
#
|
138
143
|
def remove_all_from_index!
|
139
|
-
|
144
|
+
remove_all_from_index
|
140
145
|
Sunspot.commit
|
141
146
|
end
|
142
147
|
|
@@ -182,12 +187,15 @@ module Sunspot #:nodoc:
|
|
182
187
|
unless options[:batch_size]
|
183
188
|
Sunspot.index!(all(:include => options[:include]))
|
184
189
|
else
|
185
|
-
record_count = count
|
186
|
-
counter = 1
|
187
190
|
offset = 0
|
191
|
+
counter = 1
|
192
|
+
record_count = count
|
193
|
+
last_id = 0
|
188
194
|
while(offset < record_count)
|
189
195
|
benchmark options[:batch_size], counter do
|
190
|
-
|
196
|
+
records = all(:include => options[:include], :conditions => ["#{table_name}.#{primary_key} > ?", last_id], :limit => options[:batch_size], :order => primary_key)
|
197
|
+
Sunspot.index(records)
|
198
|
+
last_id = records.last.id
|
191
199
|
end
|
192
200
|
Sunspot.commit if options[:batch_commit]
|
193
201
|
offset += options[:batch_size]
|
@@ -292,12 +300,8 @@ module Sunspot #:nodoc:
|
|
292
300
|
# Remove the model from the Solr index and commit immediately. See
|
293
301
|
# #remove_from_index
|
294
302
|
#
|
295
|
-
#---
|
296
|
-
#FIXME Sunspot should implement remove!()
|
297
|
-
#
|
298
303
|
def remove_from_index!
|
299
|
-
Sunspot.remove(self)
|
300
|
-
Sunspot.commit
|
304
|
+
Sunspot.remove!(self)
|
301
305
|
end
|
302
306
|
end
|
303
307
|
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'escape'
|
2
|
+
|
3
|
+
module Sunspot #:nodoc:
|
4
|
+
module Rails #:nodoc:
|
5
|
+
# The Sunspot::Rails::Server class is a simple wrapper around
|
6
|
+
# the start/stop scripts for solr.
|
7
|
+
class Server
|
8
|
+
|
9
|
+
class << self
|
10
|
+
delegate :log_file, :log_level, :port, :solr_home, :to => :configuration
|
11
|
+
|
12
|
+
# Name of the sunspot executable (shell script)
|
13
|
+
SUNSPOT_EXECUTABLE = (RUBY_PLATFORM =~ /w(in)?32$/ ? 'sunspot-solr.bat' : 'sunspot-solr')
|
14
|
+
|
15
|
+
#
|
16
|
+
# Start the sunspot-solr server. Bootstrap solr_home first,
|
17
|
+
# if neccessary.
|
18
|
+
#
|
19
|
+
# ==== Returns
|
20
|
+
#
|
21
|
+
# Boolean:: success
|
22
|
+
#
|
23
|
+
def start
|
24
|
+
bootstrap if bootstrap_neccessary?
|
25
|
+
execute( start_command )
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Run the sunspot-solr server in the foreground. Boostrap
|
30
|
+
# solr_home first, if neccessary.
|
31
|
+
#
|
32
|
+
# ==== Returns
|
33
|
+
#
|
34
|
+
# Boolean:: success
|
35
|
+
#
|
36
|
+
def run
|
37
|
+
bootstrap if bootstrap_neccessary?
|
38
|
+
execute( run_command )
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Stop the sunspot-solr server.
|
43
|
+
#
|
44
|
+
# ==== Returns
|
45
|
+
#
|
46
|
+
# Boolean:: success
|
47
|
+
#
|
48
|
+
def stop
|
49
|
+
execute( stop_command )
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Directory to store solr config files
|
54
|
+
#
|
55
|
+
# ==== Returns
|
56
|
+
#
|
57
|
+
# String:: config_path
|
58
|
+
#
|
59
|
+
def config_path
|
60
|
+
File.join( solr_home, 'conf' )
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Directory to store lucene index data files
|
65
|
+
#
|
66
|
+
# ==== Returns
|
67
|
+
#
|
68
|
+
# String:: data_path
|
69
|
+
#
|
70
|
+
def data_path
|
71
|
+
File.join( solr_home, 'data', ::Rails.env )
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Directory to store custom libraries for solr
|
76
|
+
#
|
77
|
+
# ==== Returns
|
78
|
+
#
|
79
|
+
# String:: lib_path
|
80
|
+
#
|
81
|
+
def lib_path
|
82
|
+
File.join( solr_home, 'lib' )
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Directory to store pid files
|
87
|
+
#
|
88
|
+
# ==== Returns
|
89
|
+
#
|
90
|
+
# String:: pid_path
|
91
|
+
#
|
92
|
+
def pid_path
|
93
|
+
File.join( solr_home, 'pids', ::Rails.env )
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Bootstrap a new solr_home by creating all required
|
98
|
+
# directories.
|
99
|
+
#
|
100
|
+
# ==== Returns
|
101
|
+
#
|
102
|
+
# Boolean:: success
|
103
|
+
#
|
104
|
+
def bootstrap
|
105
|
+
create_solr_directories and create_solr_configuration_files and copy_custom_solr_libraries
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Check for bootstrap necessity
|
110
|
+
#
|
111
|
+
# ==== Returns
|
112
|
+
#
|
113
|
+
# Boolean:: neccessary
|
114
|
+
#
|
115
|
+
def bootstrap_neccessary?
|
116
|
+
!File.directory?( solr_home ) or !File.exists?( File.join( config_path, 'solrconfig.xml' ) )
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
protected
|
121
|
+
|
122
|
+
#
|
123
|
+
# Generate the start command for the sunspot-solr executable
|
124
|
+
#
|
125
|
+
# ==== Returns
|
126
|
+
#
|
127
|
+
# Array:: sunspot_start_command
|
128
|
+
#
|
129
|
+
def start_command
|
130
|
+
[ SUNSPOT_EXECUTABLE, 'start', '-p', port.to_s, '-d', data_path, '-s', solr_home, '-l', log_level, '--log-file', log_file ]
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Generate the stop command for the sunspot-solr executable
|
135
|
+
#
|
136
|
+
# ==== Returns
|
137
|
+
#
|
138
|
+
# Array:: sunspot_stop_command
|
139
|
+
#
|
140
|
+
def stop_command
|
141
|
+
[ SUNSPOT_EXECUTABLE, 'stop' ]
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Generate the run command for the sunspot-solr executable
|
146
|
+
#
|
147
|
+
# ==== Returns
|
148
|
+
#
|
149
|
+
# Array:: run_command
|
150
|
+
#
|
151
|
+
def run_command
|
152
|
+
[ SUNSPOT_EXECUTABLE, 'run', '-p', port.to_s, '-d', data_path, '-s', solr_home, '-l', log_level, '-lf', log_file ]
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# access to the Sunspot::Rails::Configuration, defined in
|
157
|
+
# sunspot.yml. Use Sunspot::Rails.configuration if you want
|
158
|
+
# to access the configuration directly.
|
159
|
+
#
|
160
|
+
# ==== returns
|
161
|
+
#
|
162
|
+
# Sunspot::Rails::Configuration:: configuration
|
163
|
+
#
|
164
|
+
def configuration
|
165
|
+
Sunspot::Rails.configuration
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
#
|
171
|
+
# Change directory to the pid file path and execute a
|
172
|
+
# command on a subshell.
|
173
|
+
#
|
174
|
+
# ==== Returns
|
175
|
+
#
|
176
|
+
# Boolean:: success
|
177
|
+
#
|
178
|
+
def execute( command )
|
179
|
+
success = false
|
180
|
+
FileUtils.cd( pid_path ) do
|
181
|
+
success = Kernel.system(Escape.shell_command( command ))
|
182
|
+
end
|
183
|
+
success
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Create new solr_home, config, log and pid directories
|
188
|
+
#
|
189
|
+
# ==== Returns
|
190
|
+
#
|
191
|
+
# Boolean:: success
|
192
|
+
#
|
193
|
+
def create_solr_directories
|
194
|
+
[ solr_home, config_path, data_path, pid_path, lib_path ].each do |path|
|
195
|
+
FileUtils.mkdir_p( path )
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# Copy custom solr libraries (like localsolr) to the
|
201
|
+
# lib directory
|
202
|
+
#
|
203
|
+
# ==== Returns
|
204
|
+
#
|
205
|
+
# Boolean:: success
|
206
|
+
#
|
207
|
+
def copy_custom_solr_libraries
|
208
|
+
Dir.glob( File.join( Sunspot::Configuration.solr_default_configuration_location, '..', 'lib', '*.jar') ).each do |jar_file|
|
209
|
+
FileUtils.cp( jar_file, lib_path )
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# Copy default solr configuration files from sunspot
|
215
|
+
# gem to the new solr_home/config directory
|
216
|
+
#
|
217
|
+
# ==== Returns
|
218
|
+
#
|
219
|
+
# Boolean:: success
|
220
|
+
#
|
221
|
+
def create_solr_configuration_files
|
222
|
+
Dir.glob( File.join( Sunspot::Configuration.solr_default_configuration_location, '*') ).each do |config_file|
|
223
|
+
FileUtils.cp( config_file, config_path )
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Rails
|
3
|
+
class SessionProxy
|
4
|
+
extend MonitorMixin
|
5
|
+
|
6
|
+
class <<self
|
7
|
+
def instance
|
8
|
+
synchronize do
|
9
|
+
@instance ||= new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset!
|
14
|
+
synchronize do
|
15
|
+
@instance = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private :new
|
20
|
+
end
|
21
|
+
|
22
|
+
delegate :new_search, :search, :to => :read_session
|
23
|
+
delegate :index, :index!, :commit, :remove, :remove!, :remove_by_id,
|
24
|
+
:remove_by_id!, :remove_all, :remove_all!, :dirty?, :commit_if_dirty, :batch,
|
25
|
+
:to => :write_session
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@configuration = Sunspot::Rails::Configuration.new
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def read_session
|
34
|
+
Thread.current[:sunspot_rails_read_session] ||=
|
35
|
+
begin
|
36
|
+
session = Sunspot::Session.new
|
37
|
+
session.config.solr.url = URI::HTTP.build(
|
38
|
+
:host => @configuration.hostname,
|
39
|
+
:port => @configuration.port,
|
40
|
+
:path => @configuration.path
|
41
|
+
).to_s
|
42
|
+
session
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_session
|
47
|
+
Thread.current[:sunspot_rails_write_session] ||=
|
48
|
+
if @configuration.has_master?
|
49
|
+
master_session = Sunspot::Session.new
|
50
|
+
master_session.config.solr.url = URI::HTTP.build(
|
51
|
+
:host => configuration.master_hostname,
|
52
|
+
:port => configuration.master_port,
|
53
|
+
:path => configuration.master_path
|
54
|
+
).to_s
|
55
|
+
master_session
|
56
|
+
else
|
57
|
+
read_session
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/sunspot/rails/tasks.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'escape'
|
2
|
-
|
3
1
|
namespace :sunspot do
|
4
2
|
namespace :solr do
|
5
3
|
desc 'Start the Solr instance'
|
@@ -7,47 +5,31 @@ namespace :sunspot do
|
|
7
5
|
if RUBY_PLATFORM =~ /w(in)?32$/
|
8
6
|
abort('This command does not work on Windows. Please use rake sunspot:solr:run to run Solr in the foreground.')
|
9
7
|
end
|
10
|
-
|
11
|
-
pid_path = File.join(::Rails.root, 'solr', 'pids', ::Rails.env)
|
12
|
-
solr_home =
|
13
|
-
if %w(solrconfig schema).all? { |file| File.exist?(File.join(::Rails.root, 'solr', 'conf', "#{file}.xml")) }
|
14
|
-
File.join(::Rails.root, 'solr')
|
15
|
-
end
|
16
|
-
[data_path, pid_path].each { |path| FileUtils.mkdir_p(path) }
|
17
|
-
port = Sunspot::Rails.configuration.port
|
18
|
-
FileUtils.cd(File.join(pid_path)) do
|
19
|
-
command = ['sunspot-solr', 'start', '-p', port.to_s, '-d', data_path]
|
20
|
-
if solr_home
|
21
|
-
command << '-s' << solr_home
|
22
|
-
end
|
23
|
-
system(Escape.shell_command(command))
|
24
|
-
end
|
8
|
+
Sunspot::Rails::Server.start
|
25
9
|
end
|
26
10
|
|
27
11
|
desc 'Run the Solr instance in the foreground'
|
28
12
|
task :run => :environment do
|
29
|
-
|
30
|
-
solr_home =
|
31
|
-
if %w(solrconfig schema).all? { |file| File.exist?(File.join(::Rails.root, 'solr', 'conf', "#{file}.xml")) }
|
32
|
-
File.join(::Rails.root, 'solr')
|
33
|
-
end
|
34
|
-
FileUtils.mkdir_p(data_path)
|
35
|
-
port = Sunspot::Rails.configuration.port
|
36
|
-
command = ['sunspot-solr', 'run', '-p', port.to_s, '-d', data_path]
|
37
|
-
if RUBY_PLATFORM =~ /w(in)?32$/
|
38
|
-
command.first << '.bat'
|
39
|
-
end
|
40
|
-
if solr_home
|
41
|
-
command << '-s' << solr_home
|
42
|
-
end
|
43
|
-
exec(Escape.shell_command(command))
|
13
|
+
Sunspot::Rails::Server.run
|
44
14
|
end
|
45
15
|
|
46
16
|
desc 'Stop the Solr instance'
|
47
17
|
task :stop => :environment do
|
48
|
-
|
49
|
-
|
18
|
+
if RUBY_PLATFORM =~ /w(in)?32$/
|
19
|
+
abort('This command does not work on Windows.')
|
20
|
+
end
|
21
|
+
Sunspot::Rails::Server.stop
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Reindex all solr models'
|
25
|
+
task :reindex => :environment do
|
26
|
+
all_files = Dir.glob(File.join(RAILS_ROOT, 'app', 'models', '*.rb'))
|
27
|
+
all_models = all_files.map { |path| File.basename(path, '.rb').camelize.constantize }
|
28
|
+
sunspot_models = all_models.select { |m| m < ActiveRecord::Base and m.searchable? }
|
29
|
+
|
30
|
+
sunspot_models.each do |model|
|
31
|
+
model.reindex :batch_commit => false
|
50
32
|
end
|
51
33
|
end
|
52
34
|
end
|
53
|
-
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'escape'
|
2
|
+
|
3
|
+
module Sunspot #:nodoc:
|
4
|
+
module Rails #:nodoc:
|
5
|
+
class Util
|
6
|
+
class << self
|
7
|
+
def sunspot_options
|
8
|
+
@sunspot_options ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def index_relevant_attribute_changed?( object )
|
12
|
+
class_key = object.class.to_s.underscore.to_sym
|
13
|
+
ignore_attributes = (sunspot_options[class_key][:ignore_attribute_changes_of] || [])
|
14
|
+
!(object.changes.symbolize_keys.keys - ignore_attributes).blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|