ebeigarts-thinking-sphinx 1.1.21

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.
Files changed (91) hide show
  1. data/LICENCE +20 -0
  2. data/README.textile +143 -0
  3. data/lib/thinking_sphinx.rb +217 -0
  4. data/lib/thinking_sphinx/active_record.rb +278 -0
  5. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  6. data/lib/thinking_sphinx/active_record/delta.rb +87 -0
  7. data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
  8. data/lib/thinking_sphinx/active_record/search.rb +57 -0
  9. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +53 -0
  10. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
  11. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +135 -0
  12. data/lib/thinking_sphinx/association.rb +164 -0
  13. data/lib/thinking_sphinx/attribute.rb +269 -0
  14. data/lib/thinking_sphinx/class_facet.rb +15 -0
  15. data/lib/thinking_sphinx/collection.rb +148 -0
  16. data/lib/thinking_sphinx/configuration.rb +275 -0
  17. data/lib/thinking_sphinx/core/string.rb +15 -0
  18. data/lib/thinking_sphinx/deltas.rb +30 -0
  19. data/lib/thinking_sphinx/deltas/datetime_delta.rb +50 -0
  20. data/lib/thinking_sphinx/deltas/default_delta.rb +68 -0
  21. data/lib/thinking_sphinx/deltas/delayed_delta.rb +27 -0
  22. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +24 -0
  23. data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +27 -0
  24. data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +26 -0
  25. data/lib/thinking_sphinx/deploy/capistrano.rb +82 -0
  26. data/lib/thinking_sphinx/facet.rb +108 -0
  27. data/lib/thinking_sphinx/facet_collection.rb +59 -0
  28. data/lib/thinking_sphinx/field.rb +82 -0
  29. data/lib/thinking_sphinx/index.rb +99 -0
  30. data/lib/thinking_sphinx/index/builder.rb +287 -0
  31. data/lib/thinking_sphinx/index/faux_column.rb +110 -0
  32. data/lib/thinking_sphinx/property.rb +160 -0
  33. data/lib/thinking_sphinx/rails_additions.rb +136 -0
  34. data/lib/thinking_sphinx/search.rb +727 -0
  35. data/lib/thinking_sphinx/search/facets.rb +104 -0
  36. data/lib/thinking_sphinx/source.rb +175 -0
  37. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  38. data/lib/thinking_sphinx/source/sql.rb +126 -0
  39. data/lib/thinking_sphinx/tasks.rb +245 -0
  40. data/rails/init.rb +14 -0
  41. data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +136 -0
  42. data/spec/unit/thinking_sphinx/active_record/has_many_association_spec.rb +53 -0
  43. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +107 -0
  44. data/spec/unit/thinking_sphinx/active_record_spec.rb +329 -0
  45. data/spec/unit/thinking_sphinx/association_spec.rb +246 -0
  46. data/spec/unit/thinking_sphinx/attribute_spec.rb +338 -0
  47. data/spec/unit/thinking_sphinx/collection_spec.rb +15 -0
  48. data/spec/unit/thinking_sphinx/configuration_spec.rb +222 -0
  49. data/spec/unit/thinking_sphinx/core/string_spec.rb +9 -0
  50. data/spec/unit/thinking_sphinx/facet_collection_spec.rb +64 -0
  51. data/spec/unit/thinking_sphinx/facet_spec.rb +302 -0
  52. data/spec/unit/thinking_sphinx/field_spec.rb +154 -0
  53. data/spec/unit/thinking_sphinx/index/builder_spec.rb +355 -0
  54. data/spec/unit/thinking_sphinx/index/faux_column_spec.rb +30 -0
  55. data/spec/unit/thinking_sphinx/index_spec.rb +45 -0
  56. data/spec/unit/thinking_sphinx/rails_additions_spec.rb +191 -0
  57. data/spec/unit/thinking_sphinx/search_spec.rb +228 -0
  58. data/spec/unit/thinking_sphinx/source_spec.rb +217 -0
  59. data/spec/unit/thinking_sphinx_spec.rb +151 -0
  60. data/tasks/distribution.rb +67 -0
  61. data/tasks/rails.rake +1 -0
  62. data/tasks/testing.rb +100 -0
  63. data/vendor/after_commit/LICENSE +20 -0
  64. data/vendor/after_commit/README +16 -0
  65. data/vendor/after_commit/Rakefile +22 -0
  66. data/vendor/after_commit/init.rb +8 -0
  67. data/vendor/after_commit/lib/after_commit.rb +45 -0
  68. data/vendor/after_commit/lib/after_commit/active_record.rb +114 -0
  69. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +103 -0
  70. data/vendor/after_commit/test/after_commit_test.rb +53 -0
  71. data/vendor/delayed_job/lib/delayed/job.rb +251 -0
  72. data/vendor/delayed_job/lib/delayed/message_sending.rb +7 -0
  73. data/vendor/delayed_job/lib/delayed/performable_method.rb +55 -0
  74. data/vendor/delayed_job/lib/delayed/worker.rb +54 -0
  75. data/vendor/riddle/lib/riddle.rb +30 -0
  76. data/vendor/riddle/lib/riddle/client.rb +619 -0
  77. data/vendor/riddle/lib/riddle/client/filter.rb +53 -0
  78. data/vendor/riddle/lib/riddle/client/message.rb +65 -0
  79. data/vendor/riddle/lib/riddle/client/response.rb +84 -0
  80. data/vendor/riddle/lib/riddle/configuration.rb +33 -0
  81. data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +48 -0
  82. data/vendor/riddle/lib/riddle/configuration/index.rb +142 -0
  83. data/vendor/riddle/lib/riddle/configuration/indexer.rb +19 -0
  84. data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
  85. data/vendor/riddle/lib/riddle/configuration/searchd.rb +25 -0
  86. data/vendor/riddle/lib/riddle/configuration/section.rb +43 -0
  87. data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
  88. data/vendor/riddle/lib/riddle/configuration/sql_source.rb +34 -0
  89. data/vendor/riddle/lib/riddle/configuration/xml_source.rb +28 -0
  90. data/vendor/riddle/lib/riddle/controller.rb +44 -0
  91. metadata +191 -0
@@ -0,0 +1,245 @@
1
+ require 'fileutils'
2
+
3
+ namespace :thinking_sphinx do
4
+ task :app_env do
5
+ if defined?(RAILS_ROOT)
6
+ Rake::Task[:environment].invoke
7
+ Rails.configuration.cache_classes = false
8
+ end
9
+
10
+ Rake::Task[:merb_env].invoke if defined?(Merb)
11
+ end
12
+
13
+ desc "Output the current Thinking Sphinx version"
14
+ task :version => :app_env do
15
+ puts "Thinking Sphinx v" + ThinkingSphinx::Version::String
16
+ end
17
+
18
+ desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
19
+ task :running_start => :app_env do
20
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
21
+ Rake::Task["thinking_sphinx:start"].invoke
22
+ end
23
+
24
+ desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
25
+ task :start => :app_env do
26
+ config = ThinkingSphinx::Configuration.instance
27
+
28
+ FileUtils.mkdir_p config.searchd_file_path
29
+ raise RuntimeError, "searchd is already running." if sphinx_running?
30
+
31
+ Dir["#{config.searchd_file_path}/*.spl"].each { |file| File.delete(file) }
32
+
33
+ system! "#{config.bin_path}#{config.searchd_binary_name} --pidfile --config #{config.config_file}"
34
+
35
+ sleep(2)
36
+
37
+ if sphinx_running?
38
+ puts "Started successfully (pid #{sphinx_pid})."
39
+ else
40
+ puts "Failed to start searchd daemon. Check #{config.searchd_log_file}"
41
+ end
42
+ end
43
+
44
+ desc "Stop Sphinx using Thinking Sphinx's settings"
45
+ task :stop => :app_env do
46
+ raise RuntimeError, "searchd is not running." unless sphinx_running?
47
+ config = ThinkingSphinx::Configuration.instance
48
+ pid = sphinx_pid
49
+ system! "#{config.bin_path}#{config.searchd_binary_name} --stop --config #{config.config_file}"
50
+ puts "Stopped search daemon (pid #{pid})."
51
+ end
52
+
53
+ desc "Restart Sphinx"
54
+ task :restart => [:app_env, :stop, :start]
55
+
56
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
57
+ task :configure => :app_env do
58
+ config = ThinkingSphinx::Configuration.instance
59
+ puts "Generating Configuration to #{config.config_file}"
60
+ config.build
61
+ end
62
+
63
+ desc "Index data for Sphinx using Thinking Sphinx's settings"
64
+ task :index => :app_env do
65
+ ThinkingSphinx::Deltas::Job.cancel_thinking_sphinx_jobs
66
+
67
+ config = ThinkingSphinx::Configuration.instance
68
+ unless ENV["INDEX_ONLY"] == "true"
69
+ puts "Generating Configuration to #{config.config_file}"
70
+ config.build
71
+ end
72
+
73
+ FileUtils.mkdir_p config.searchd_file_path
74
+ cmd = "#{config.bin_path}#{config.indexer_binary_name} --config #{config.config_file} --all"
75
+ cmd << " --rotate" if sphinx_running?
76
+
77
+ system! cmd
78
+ end
79
+
80
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
81
+ task :rebuild => :app_env do
82
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
83
+ Rake::Task["thinking_sphinx:index"].invoke
84
+ Rake::Task["thinking_sphinx:start"].invoke
85
+ end
86
+
87
+ namespace :index do
88
+ task :delta => :app_env do
89
+ ThinkingSphinx.indexed_models.select { |model|
90
+ model.constantize.sphinx_indexes.any? { |index| index.delta? }
91
+ }.each do |model|
92
+ model.constantize.sphinx_indexes.select { |index|
93
+ index.delta? && index.delta_object.respond_to?(:delayed_index)
94
+ }.each { |index|
95
+ index.delta_object.delayed_index(index.model)
96
+ }
97
+ end
98
+ end
99
+ end
100
+
101
+ desc "Process stored delta index requests"
102
+ task :delayed_delta => :app_env do
103
+ require 'delayed/worker'
104
+
105
+ Delayed::Worker.new(
106
+ :min_priority => ENV['MIN_PRIORITY'],
107
+ :max_priority => ENV['MAX_PRIORITY']
108
+ ).start
109
+ end
110
+
111
+ # http://www.sphinxsearch.com/docs/current.html#xmlpipe2
112
+ desc "Streams XML data to STDOUT"
113
+ task :xml => :app_env do
114
+ source_name = ENV["NAME"]
115
+ # STDERR.puts "Source name: #{source_name}"
116
+ source_name =~ /^(.+)_(delta|core)_(\d+)$/
117
+ sphinx_name = $1
118
+ index_name = "#{$1}_#{$2}"
119
+ offset = ENV["OFFSET"]
120
+ model_name = ThinkingSphinx.indexed_models.detect { |s| s.constantize.send(:sphinx_name) == sphinx_name }
121
+ # STDERR.puts "Model name: #{model_name}"
122
+ model_klass = model_name.constantize
123
+
124
+ # Do not use xml type in rake task
125
+ ThinkingSphinx::Configuration.instance.type = "sql"
126
+
127
+ # Get TS index configuration
128
+ index_configuration = model_klass.to_riddle(offset).detect { |c| c.name == index_name }
129
+ source = index_configuration.sources.first
130
+
131
+ # get $start, $end
132
+ # STDERR.puts source.sql_query_range
133
+ range_start, range_end = model_klass.connection.select_rows(source.sql_query_range).first.collect(&:to_i)
134
+ query = source.sql_query.gsub('$start', range_start.to_s).gsub('$end', range_end.to_s)
135
+
136
+ # fetch sql and generate xml
137
+ puts %{<?xml version="1.0" encoding="utf-8"?>}
138
+ puts %{<sphinx:docset>}
139
+
140
+ # results = model_klass.connection.select_all(query)
141
+ # STDERR.puts "fetching #{start_id}.. "
142
+ # STDERR.puts query
143
+ model_klass.sphinx_database_adapter.select_each(query) do |values|
144
+ id = values.delete "id"
145
+ puts %{<sphinx:document id="#{id.to_i}">}
146
+ values.each do |k, v|
147
+ if source.sql_attr_bool.include?(k.to_sym)
148
+ v = ['Y', 'T', '1', 1, true].include?(v) ? 1 : 0
149
+ elsif source.sql_attr_uint.include?(k.to_sym) ||
150
+ source.sql_attr_timestamp.include?(k.to_sym)
151
+ v = v.to_i
152
+ elsif source.sql_attr_float.include?(k.to_sym)
153
+ v = v.to_f
154
+ else
155
+ v = value_to_string(v)
156
+ v = %{<![CDATA[[#{v}]]>}
157
+ end
158
+ puts %{<#{k}>#{v}</#{k}>}
159
+ end
160
+ # Add MVA attributes (:ranged_query, :query)
161
+ internal_id = values["sphinx_internal_id"]
162
+ source.sql_attr_multi.each do |params|
163
+ # STDERR.puts "MVA_ATTRS: #{params.inspect}"
164
+ mva_definition, mva_query, mva_query_range = params.split(";")
165
+ k = mva_definition.split(" ")[1]
166
+ if mva_query
167
+ mva_query = mva_query.gsub('$start', internal_id.to_s).gsub('$end', internal_id.to_s)
168
+ printf %{<#{k}>}
169
+ not_first = false
170
+ model_klass.sphinx_database_adapter.select_each(mva_query) do |values|
171
+ if not_first
172
+ printf ","
173
+ else
174
+ not_first = true
175
+ end
176
+ printf values.values.first.to_s
177
+ end
178
+ puts %{</#{k}>}
179
+ end
180
+ end
181
+ puts %{</sphinx:document>}
182
+ end
183
+
184
+ puts %{</sphinx:docset>}
185
+ end
186
+
187
+ # try to remove invalid xml characters
188
+ def value_to_string(v)
189
+ v.is_a?(String) ? v.gsub("\000", '') : v
190
+ end
191
+ end
192
+
193
+ namespace :ts do
194
+ desc "Output the current Thinking Sphinx version"
195
+ task :version => "thinking_sphinx:version"
196
+ desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
197
+ task :run => "thinking_sphinx:running_start"
198
+ desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
199
+ task :start => "thinking_sphinx:start"
200
+ desc "Stop Sphinx using Thinking Sphinx's settings"
201
+ task :stop => "thinking_sphinx:stop"
202
+ desc "Index data for Sphinx using Thinking Sphinx's settings"
203
+ task :in => "thinking_sphinx:index"
204
+ namespace :in do
205
+ desc "Index Thinking Sphinx datetime delta indexes"
206
+ task :delta => "thinking_sphinx:index:delta"
207
+ end
208
+ task :index => "thinking_sphinx:index"
209
+ desc "Restart Sphinx"
210
+ task :restart => "thinking_sphinx:restart"
211
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
212
+ task :conf => "thinking_sphinx:configure"
213
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
214
+ task :config => "thinking_sphinx:configure"
215
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
216
+ task :rebuild => "thinking_sphinx:rebuild"
217
+ desc "Process stored delta index requests"
218
+ task :dd => "thinking_sphinx:delayed_delta"
219
+ desc "Streams XML data to STDOUT"
220
+ task :xml => "thinking_sphinx:xml"
221
+ end
222
+
223
+ def sphinx_pid
224
+ ThinkingSphinx.sphinx_pid
225
+ end
226
+
227
+ def sphinx_running?
228
+ ThinkingSphinx.sphinx_running?
229
+ end
230
+
231
+ # a fail-fast, hopefully helpful version of system
232
+ def system!(cmd)
233
+ unless system(cmd)
234
+ raise <<-SYSTEM_CALL_FAILED
235
+ The following command failed:
236
+ #{cmd}
237
+
238
+ This could be caused by a PATH issue in the environment of cron/passenger/etc. Your current PATH:
239
+ #{ENV['PATH']}
240
+ You can set the path to your indexer and searchd binaries using the bin_path property in config/sphinx.yml:
241
+ production:
242
+ bin_path: '/usr/local/bin'
243
+ SYSTEM_CALL_FAILED
244
+ end
245
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'thinking_sphinx'
2
+ require 'action_controller/dispatcher'
3
+
4
+ ActionController::Dispatcher.to_prepare :thinking_sphinx do
5
+ # Force internationalisation to be loaded.
6
+ if Rails::VERSION::STRING.to_f > 2.2
7
+ I18n.backend.reload!
8
+ I18n.backend.available_locales
9
+ elsif Rails::VERSION::STRING.to_f > 2.1
10
+ I18n.backend.load_translations(*I18n.load_path)
11
+ end
12
+
13
+ ThinkingSphinx::Configuration.instance.load_models
14
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe "ThinkingSphinx::ActiveRecord::Delta" do
4
+ it "should call the toggle_delta method after a save" do
5
+ @beta = Beta.new(:name => 'beta')
6
+ @beta.stub_method(:toggle_delta => true)
7
+
8
+ @beta.save
9
+
10
+ @beta.should have_received(:toggle_delta)
11
+ end
12
+
13
+ it "should call the toggle_delta method after a save!" do
14
+ @beta = Beta.new(:name => 'beta')
15
+ @beta.stub_method(:toggle_delta => true)
16
+
17
+ @beta.save!
18
+
19
+ @beta.should have_received(:toggle_delta)
20
+ end
21
+
22
+ describe "suspended_delta method" do
23
+ before :each do
24
+ ThinkingSphinx.stub_method(:deltas_enabled? => true)
25
+ Person.sphinx_indexes.first.delta_object.stub_method(:` => "")
26
+ end
27
+
28
+ it "should execute the argument block with deltas disabled" do
29
+ ThinkingSphinx.should_receive(:deltas_enabled=).once.with(false)
30
+ ThinkingSphinx.should_receive(:deltas_enabled=).once.with(true)
31
+ lambda { Person.suspended_delta { raise 'i was called' } }.should(
32
+ raise_error(Exception)
33
+ )
34
+ end
35
+
36
+ it "should restore deltas_enabled to its original setting" do
37
+ ThinkingSphinx.stub_method(:deltas_enabled? => false)
38
+ ThinkingSphinx.should_receive(:deltas_enabled=).twice.with(false)
39
+ Person.suspended_delta { 'no-op' }
40
+ end
41
+
42
+ it "should restore deltas_enabled to its original setting even if there was an exception" do
43
+ ThinkingSphinx.stub_method(:deltas_enabled? => false)
44
+ ThinkingSphinx.should_receive(:deltas_enabled=).twice.with(false)
45
+ lambda { Person.suspended_delta { raise 'bad error' } }.should(
46
+ raise_error(Exception)
47
+ )
48
+ end
49
+
50
+ it "should reindex by default after the code block is run" do
51
+ Person.should_receive(:index_delta)
52
+ Person.suspended_delta { 'no-op' }
53
+ end
54
+
55
+ it "should not reindex after the code block if false is passed in" do
56
+ Person.should_not_receive(:index_delta)
57
+ Person.suspended_delta(false) { 'no-op' }
58
+ end
59
+ end
60
+
61
+ describe "toggle_delta method" do
62
+ it "should set the delta value to true" do
63
+ @person = Person.new
64
+
65
+ @person.delta.should be_false
66
+ @person.send(:toggle_delta)
67
+ @person.delta.should be_true
68
+ end
69
+ end
70
+
71
+ describe "index_delta method" do
72
+ before :each do
73
+ ThinkingSphinx::Configuration.stub_method(:environment => "spec")
74
+ ThinkingSphinx.stub_method(:deltas_enabled? => true, :sphinx_running? => true)
75
+ Person.delta_object.stub_methods(:` => "", :toggled => true)
76
+
77
+ @person = Person.new
78
+ @person.stub_method(
79
+ :in_both_indexes? => false,
80
+ :sphinx_document_id => 1
81
+ )
82
+
83
+ @client = Riddle::Client.new
84
+ @client.stub!(:update => true)
85
+ Riddle::Client.stub_method(:new => @client)
86
+ end
87
+
88
+ it "shouldn't index if delta indexing is disabled" do
89
+ ThinkingSphinx.stub_method(:deltas_enabled? => false)
90
+
91
+ @person.send(:index_delta)
92
+
93
+ Person.sphinx_indexes.first.delta_object.should_not have_received(:`)
94
+ @client.should_not have_received(:update)
95
+ end
96
+
97
+ it "shouldn't index if index updating is disabled" do
98
+ ThinkingSphinx.stub_method(:updates_enabled? => false)
99
+
100
+ @person.send(:index_delta)
101
+
102
+ Person.sphinx_indexes.first.delta_object.should_not have_received(:`)
103
+ end
104
+
105
+ it "shouldn't index if the environment is 'test'" do
106
+ ThinkingSphinx.unstub_method(:deltas_enabled?)
107
+ ThinkingSphinx.deltas_enabled = nil
108
+ ThinkingSphinx::Configuration.stub_method(:environment => "test")
109
+
110
+ @person.send(:index_delta)
111
+
112
+ Person.sphinx_indexes.first.delta_object.should_not have_received(:`)
113
+ end
114
+
115
+ it "should call indexer for the delta index" do
116
+ @person.send(:index_delta)
117
+
118
+ Person.sphinx_indexes.first.delta_object.should have_received(:`).with(
119
+ "#{ThinkingSphinx::Configuration.instance.bin_path}indexer --config #{ThinkingSphinx::Configuration.instance.config_file} --rotate person_delta"
120
+ )
121
+ end
122
+
123
+ it "shouldn't update the deleted attribute if not in the index" do
124
+ @client.should_not_receive(:update)
125
+
126
+ @person.send(:index_delta)
127
+ end
128
+
129
+ it "should update the deleted attribute if in the core index" do
130
+ @person.stub_method(:in_both_indexes? => true)
131
+ @client.should_receive(:update)
132
+
133
+ @person.send(:index_delta)
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe 'ThinkingSphinx::ActiveRecord::HasManyAssociation' do
4
+ describe "search method" do
5
+ before :each do
6
+ Friendship.stub_method(:search => true)
7
+
8
+ @person = Person.find(:first)
9
+ @index = Friendship.sphinx_indexes.first
10
+ end
11
+
12
+ it "should raise an error if the required attribute doesn't exist" do
13
+ @index.stub_method(:attributes => [])
14
+
15
+ lambda { @person.friendships.search "test" }.should raise_error(RuntimeError)
16
+
17
+ @index.unstub_method(:attributes)
18
+ end
19
+
20
+ it "should add a filter for the attribute into a normal search call" do
21
+ @person.friendships.search "test"
22
+
23
+ Friendship.should have_received(:search).with(
24
+ "test", :with => {:person_id => @person.id}
25
+ )
26
+ end
27
+ end
28
+
29
+ describe "search method for has_many :through" do
30
+ before :each do
31
+ Person.stub_method(:search => true)
32
+
33
+ @person = Person.find(:first)
34
+ @index = Person.sphinx_indexes.first
35
+ end
36
+
37
+ it "should raise an error if the required attribute doesn't exist" do
38
+ @index.stub_method(:attributes => [])
39
+
40
+ lambda { @person.friends.search "test" }.should raise_error(RuntimeError)
41
+
42
+ @index.unstub_method(:attributes)
43
+ end
44
+
45
+ it "should add a filter for the attribute into a normal search call" do
46
+ @person.friends.search "test"
47
+
48
+ Person.should have_received(:search).with(
49
+ "test", :with => {:friendly_ids => @person.id}
50
+ )
51
+ end
52
+ end
53
+ end