diff --git a/HISTORY b/HISTORY index 803bcd0d1..38ca1571f 100644 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,10 @@ +2017-09-29: 3.4.2 +* [FIX] Real-time callback syntax for namespaced models accepts a string (as documented). +* [CHANGE] Allow use of deletion callbacks for rollback events. +* [CHANGE] Remove extra deletion code in the Populator - it's also being done by the real-time rake interface. +* [FIX] Fix up logged warnings. +* [FIX] Add missing search options to known values to avoid incorrect warnings. + 2017-08-29: 3.4.1 * [CHANGE] Treat "Lost connection to MySQL server" as a connection error (Manuel Schnitzer). * [FIX] Index normalisation will now work even when index model tables don't exist. diff --git a/README.textile b/README.textile index dbf8a3968..29c8be1e1 100644 --- a/README.textile +++ b/README.textile @@ -1,11 +1,12 @@ h1. Thinking Sphinx -Thinking Sphinx is a library for connecting ActiveRecord to the Sphinx full-text search tool, and integrates closely with Rails (but also works with other Ruby web frameworks). The current release is v3.4.1. +Thinking Sphinx is a library for connecting ActiveRecord to the Sphinx full-text search tool, and integrates closely with Rails (but also works with other Ruby web frameworks). The current release is v3.4.2. h2. Upgrading Please refer to the release notes for any changes you need to make when upgrading: +* "v3.4.2":https://github.com/pat/thinking-sphinx/releases/tag/v3.4.2 * "v3.4.1":https://github.com/pat/thinking-sphinx/releases/tag/v3.4.1 * "v3.4.0":https://github.com/pat/thinking-sphinx/releases/tag/v3.4.0 * "v3.3.0":https://github.com/pat/thinking-sphinx/releases/tag/v3.3.0 @@ -25,7 +26,7 @@ It's a gem, so install it like you would any other gem. You will also need to sp
gem 'mysql2',          '~> 0.3', :platform => :ruby
 gem 'jdbc-mysql',      '= 5.1.35', :platform => :jruby
-gem 'thinking-sphinx', '~> 3.4.1'
+gem 'thinking-sphinx', '~> 3.4.2' The MySQL gems mentioned are required for connecting to Sphinx, so please include it even when you're using PostgreSQL for your database. If you're using JRuby, there is "currently an issue with Sphinx and jdbc-mysql 5.1.36 or newer":http://sphinxsearch.com/forum/view.html?id=13939, so you'll need to stick to nothing more recent than 5.1.35. diff --git a/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb b/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb index 88983a4ba..1dbeeeadf 100644 --- a/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +++ b/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb @@ -1,9 +1,19 @@ class ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks < ThinkingSphinx::Callbacks - callbacks :after_destroy + callbacks :after_destroy, :after_rollback def after_destroy + delete_from_sphinx + end + + def after_rollback + delete_from_sphinx + end + + private + + def delete_from_sphinx return if ThinkingSphinx::Callbacks.suspended? || instance.new_record? indices.each { |index| @@ -11,8 +21,6 @@ def after_destroy } end - private - def indices ThinkingSphinx::Configuration.instance.index_set_class.new( :classes => [instance.class] diff --git a/lib/thinking_sphinx/active_record/log_subscriber.rb b/lib/thinking_sphinx/active_record/log_subscriber.rb index 76af6e572..5cbad52c3 100644 --- a/lib/thinking_sphinx/active_record/log_subscriber.rb +++ b/lib/thinking_sphinx/active_record/log_subscriber.rb @@ -14,9 +14,9 @@ def query(event) debug " #{identifier} #{event.payload[:query]}" end - def warn(event) + def caution(event) identifier = color 'Sphinx', GREEN, true - warn " #{identifier} #{event.payload[:guard]}" + warn " #{identifier} #{event.payload[:caution]}" end end diff --git a/lib/thinking_sphinx/middlewares/valid_options.rb b/lib/thinking_sphinx/middlewares/valid_options.rb index d2d164a9c..7ad1a5722 100644 --- a/lib/thinking_sphinx/middlewares/valid_options.rb +++ b/lib/thinking_sphinx/middlewares/valid_options.rb @@ -13,7 +13,7 @@ def check_options(options) unknown = invalid_keys options.keys return if unknown.empty? - ThinkingSphinx::Logger.log :warn, + ThinkingSphinx::Logger.log :caution, "Unexpected search options: #{unknown.inspect}" end diff --git a/lib/thinking_sphinx/real_time.rb b/lib/thinking_sphinx/real_time.rb index 024195d4e..6b1a94c07 100644 --- a/lib/thinking_sphinx/real_time.rb +++ b/lib/thinking_sphinx/real_time.rb @@ -4,7 +4,7 @@ module Callbacks end def self.callback_for(reference, path = [], &block) - Callbacks::RealTimeCallbacks.new reference, path, &block + Callbacks::RealTimeCallbacks.new reference.to_sym, path, &block end end diff --git a/lib/thinking_sphinx/real_time/populator.rb b/lib/thinking_sphinx/real_time/populator.rb index 1250fe864..d6eab2cec 100644 --- a/lib/thinking_sphinx/real_time/populator.rb +++ b/lib/thinking_sphinx/real_time/populator.rb @@ -10,8 +10,6 @@ def initialize(index) def populate(&block) instrument 'start_populating' - remove_files - scope.find_in_batches(:batch_size => batch_size) do |instances| transcriber.copy *instances instrument 'populated', :instances => instances @@ -38,10 +36,6 @@ def instrument(message, options = {}) ) end - def remove_files - Dir["#{index.path}*"].each { |file| FileUtils.rm file } - end - def transcriber @transcriber ||= ThinkingSphinx::RealTime::Transcriber.new index end diff --git a/lib/thinking_sphinx/search.rb b/lib/thinking_sphinx/search.rb index 33160613b..bb2a53885 100644 --- a/lib/thinking_sphinx/search.rb +++ b/lib/thinking_sphinx/search.rb @@ -6,6 +6,15 @@ class ThinkingSphinx::Search < Array respond_to_missing? send should should_not type ) SAFE_METHODS = %w( partition private_methods protected_methods public_methods send class ) + KNOWN_OPTIONS = ( + [ + :classes, :conditions, :geo, :group_by, :ids_only, :ignore_scopes, + :indices, :limit, :masks, :max_matches, :middleware, :offset, :order, + :order_group_by, :page, :per_page, :populate, :retry_stale, :select, + :skip_sti, :sql, :star, :with, :with_all, :without, :without_ids + ] + + ThinkingSphinx::Middlewares::SphinxQL::SELECT_OPTIONS + ).uniq DEFAULT_MASKS = [ ThinkingSphinx::Masks::PaginationMask, ThinkingSphinx::Masks::ScopesMask, @@ -25,12 +34,7 @@ def self.valid_options @valid_options end - @valid_options = [ - :classes, :conditions, :geo, :group_by, :ids_only, :ignore_scopes, :indices, - :limit, :masks, :max_matches, :middleware, :offset, :order, :order_group_by, - :page, :per_page, :populate, :retry_stale, :select, :skip_sti, :sql, :star, - :with, :with_all, :without, :without_ids - ] + @valid_options = KNOWN_OPTIONS.dup def initialize(query = nil, options = {}) query, options = nil, query if query.is_a?(Hash) diff --git a/spec/acceptance/real_time_updates_spec.rb b/spec/acceptance/real_time_updates_spec.rb index baa7adb84..24f4deb41 100644 --- a/spec/acceptance/real_time_updates_spec.rb +++ b/spec/acceptance/real_time_updates_spec.rb @@ -14,4 +14,15 @@ expect(Product.search('blue fish', :indices => ['product_core']).to_a). to eq([product]) end + + it "handles inserts and updates for namespaced models" do + person = Admin::Person.create :name => 'Death' + + expect(Admin::Person.search('Death').to_a).to eq([person]) + + person.update_attributes :name => 'Mort' + + expect(Admin::Person.search('Death').to_a).to be_empty + expect(Admin::Person.search('Mort').to_a).to eq([person]) + end end diff --git a/spec/internal/app/indices/admin_person_index.rb b/spec/internal/app/indices/admin_person_index.rb index 94901e387..ea3c19bfa 100644 --- a/spec/internal/app/indices/admin_person_index.rb +++ b/spec/internal/app/indices/admin_person_index.rb @@ -1,3 +1,7 @@ ThinkingSphinx::Index.define 'admin/person', :with => :active_record do indexes name end + +ThinkingSphinx::Index.define 'admin/person', :with => :real_time, :name => 'admin_person_rt' do + indexes name +end diff --git a/spec/internal/app/models/admin/person.rb b/spec/internal/app/models/admin/person.rb index 2c48d632e..c6bbeeb29 100644 --- a/spec/internal/app/models/admin/person.rb +++ b/spec/internal/app/models/admin/person.rb @@ -1,3 +1,5 @@ class Admin::Person < ActiveRecord::Base self.table_name = 'admin_people' + + after_save ThinkingSphinx::RealTime.callback_for('admin/person') end diff --git a/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb b/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb index 066ef0846..666ac136e 100644 --- a/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +++ b/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb @@ -64,4 +64,63 @@ ThinkingSphinx::Callbacks.resume! end end + + describe '.after_rollback' do + let(:callbacks) { double('callbacks', :after_rollback => nil) } + + before :each do + allow(ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks). + to receive_messages :new => callbacks + end + + it "builds an object from the instance" do + expect(ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks). + to receive(:new).with(instance).and_return(callbacks) + + ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks. + after_rollback(instance) + end + + it "invokes after_rollback on the object" do + expect(callbacks).to receive(:after_rollback) + + ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks. + after_rollback(instance) + end + end + + describe '#after_rollback' do + let(:index_set) { double 'index set', :to_a => [index] } + let(:index) { double('index', :name => 'foo_core', + :document_id_for_key => 14, :type => 'plain', :distributed? => false) } + let(:instance) { double('instance', :id => 7, :new_record? => false) } + + before :each do + allow(ThinkingSphinx::IndexSet).to receive_messages :new => index_set + end + + it "performs the deletion for the index and instance" do + expect(ThinkingSphinx::Deletion).to receive(:perform).with(index, 7) + + callbacks.after_rollback + end + + it "doesn't do anything if the instance is a new record" do + allow(instance).to receive_messages :new_record? => true + + expect(ThinkingSphinx::Deletion).not_to receive(:perform) + + callbacks.after_rollback + end + + it 'does nothing if callbacks are suspended' do + ThinkingSphinx::Callbacks.suspend! + + expect(ThinkingSphinx::Deletion).not_to receive(:perform) + + callbacks.after_rollback + + ThinkingSphinx::Callbacks.resume! + end + end end diff --git a/spec/thinking_sphinx/middlewares/valid_options_spec.rb b/spec/thinking_sphinx/middlewares/valid_options_spec.rb index 840f0ee35..9fc3baaa1 100644 --- a/spec/thinking_sphinx/middlewares/valid_options_spec.rb +++ b/spec/thinking_sphinx/middlewares/valid_options_spec.rb @@ -17,7 +17,7 @@ it "adds a warning" do expect(ThinkingSphinx::Logger).to receive(:log). - with(:warn, "Unexpected search options: [:foo]") + with(:caution, "Unexpected search options: [:foo]") middleware.call [context] end diff --git a/thinking-sphinx.gemspec b/thinking-sphinx.gemspec index efc3908f8..1ac3419fc 100644 --- a/thinking-sphinx.gemspec +++ b/thinking-sphinx.gemspec @@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__) Gem::Specification.new do |s| s.name = 'thinking-sphinx' - s.version = '3.4.1' + s.version = '3.4.2' s.platform = Gem::Platform::RUBY s.authors = ["Pat Allan"] s.email = ["pat@freelancing-gods.com"]