acts_as_indexed 0.6.2

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.
@@ -0,0 +1,5 @@
1
+ rdoc
2
+ test/test.log
3
+ coverage
4
+ index
5
+ pkg
@@ -0,0 +1,90 @@
1
+ ===0.6.2 [11th June 2010]
2
+ - Now available as a Gem as well as the original plugin. [parndt - Thanks for doing most of the hard work.]
3
+
4
+ ===0.6.0 [10th June 2010]
5
+ - Now supports Rails 3.x.x as well as Rails 2.x.x.
6
+ - Added global configuration options.
7
+ - Now recommending using with_query scope for searching.
8
+ - Deprecated find_with_index and will_paginate_search methods.
9
+
10
+ ===0.5.3 [6th June 2010]
11
+ - Now supports non-standard table names automatically. [nandalopes]
12
+
13
+ ===0.5.2 [3rd May 2010]
14
+ - Fix for Errno::ERANGE error related to certain Math.log calculations. [parndt]
15
+ - Improved index detection in a shared-directory environment. [bob-p]
16
+
17
+ ===0.5.1 [11 June 2009]
18
+ - Fixed Ruby 1.8.6 compatibility.
19
+
20
+ ===0.5.0 [24 April 2009]
21
+ - Ruby 1.9 and Rails 2.3 compatibility.
22
+ - Index location can now be set. Provides Heroku compatibility.
23
+ - Better errors on bad options.
24
+ - ActiveRecord order argument overrides ranking returned by find_by_index.
25
+ - Various test environment improvements
26
+ - Various Bugfixes
27
+
28
+ ===0.4.6 [10 August 2008]
29
+ - Rolled in pagination.
30
+
31
+ ===0.4.5 [04 February 2008]
32
+ - Fixed a bug where the find_options :limit would be added to the :offset, which caused incorrectly sized collections to be returned.
33
+ - Fixed an 'ambiguous column' error when using the :includes find_options key.
34
+
35
+ ===0.4.4 [29 November 2007]
36
+ - Fixed a bug causing the weighting section of the code to error out.
37
+
38
+ ===0.4.3 [27 September 2007]
39
+ - Fixed a bug causing records to be deleted from index during record updates.
40
+
41
+ ===0.4.2 [27 September 2007]
42
+ - Fixed a bug causing identically ranked records to be lost.
43
+
44
+ ===0.4.1 [22 September 2007]
45
+ - Fixed a bug in the main search method.
46
+
47
+ ===0.4.0 [22 September 2007]
48
+ - Search results now ranked by relevance.
49
+
50
+ ===0.3.3 [20 September 2007]
51
+ - Fixed index update bug where deleted atoms were not removed from index.
52
+ - Improved performance of quoted queries.
53
+ - Improved performance of index updates.
54
+ - When building a full index, records are retrieved and indexed in batches to reduce memory consumption.
55
+
56
+ ===0.3.2 [19 September 2007]
57
+ - Fixed index update bug.
58
+
59
+ ===0.3.1 [18 September 2007]
60
+ - Added RDoc documentation comments.
61
+
62
+ ===0.3.0 [18 September 2007]
63
+ - Minor bug fixes.
64
+ - min_word_size now works properly, with quieries containing small words in
65
+ quotes or being preceded by a '+' symbol are now searched on.
66
+
67
+ ===0.2.2 [06 September 2007]
68
+ - Search now caches query results within a session. Call the search twice in an
69
+ action? Only runs once!
70
+
71
+ ===0.2.1 [05 September 2007]
72
+ - AR find options can now be passed to the search to allow finer control of
73
+ returned Model Objects.
74
+
75
+ ===0.2.0 [04 September 2007]
76
+ - Major performance improvements.
77
+ - Index segmentation can now be tuned.
78
+
79
+ ===0.1.1 [31 August 2007]
80
+ - Added a full set of tests.
81
+ - Fixed various set-manipulation based errors.
82
+ - Fixed a bug when searching for quoted phrases.
83
+
84
+ ===0.1.01 [31 August 2007]
85
+
86
+ - Fixed a casting bug occurring when adding non-string fields to the index.
87
+
88
+ ===0.1 [31 August 2007]
89
+
90
+ - Initial release.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 - 2010 Douglas Shearer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,137 @@
1
+ = acts_as_indexed
2
+
3
+ If you find this plugin useful, please consider a donation to show your
4
+ support!
5
+
6
+ http://www.paypal.com/cgi-bin/webscr?cmd=_send-money
7
+
8
+ Paypal address: mailto:dougal.s@gmail.com
9
+
10
+
11
+ == Instructions
12
+
13
+ This plugin allows boolean-queried fulltext search to be added to any Rails
14
+ app with no dependencies and minimal setup.
15
+
16
+
17
+ == Resources
18
+
19
+ === Install
20
+
21
+ == Rails 2.x.x
22
+ ./script/plugin install git://github.com/dougal/acts_as_indexed.git
23
+
24
+ == Rails 3.x.x
25
+ rails plugin install git://github.com/dougal/acts_as_indexed.git
26
+
27
+ === As a Gem
28
+ Despite this being slightly against the the original ethos of the project,
29
+ acts_as_indexed is now available as a Gem as several people have requested it.
30
+
31
+ gem install acts_as_indexed
32
+
33
+ Make sure to specify the Gem in your environment.rb file (Rails 2.x.x), or the Gemfile (Rails 3.x.x).
34
+
35
+ If you don't have git installed, you can download the plugin from the GitHub
36
+ page (http://github.com/dougal/acts_as_indexed) and unpack it into the
37
+ <tt>vendor/plugins</tt> directory of your rails app.
38
+
39
+ == Usage
40
+
41
+
42
+ === Setup
43
+
44
+ Add +acts_as_indexed+ to the top of any models you want to index, along with a
45
+ list of the fields you wish to be indexed.
46
+
47
+ class Post < ActiveRecord::Base
48
+ acts_as_indexed :fields => [:title, :body]
49
+
50
+ ...
51
+ end
52
+
53
+ The fields are not limited to model fields, but can be any instance method of
54
+ the current model.
55
+
56
+ class User < ActiveRecord::Base
57
+ acts_as_indexed :fields => [:address, :fullname]
58
+
59
+ def fullname
60
+ self.firstname + ' ' + self.lastname
61
+ end
62
+
63
+ ...
64
+ end
65
+
66
+ Any of the configuration options in the Further Configuration section can be added as to the acts_as_indexed method call. These will override any defaults or global configuration.
67
+
68
+
69
+ === Searching
70
+
71
+ To search, call the +with_query+ named scope on your model, passing a query as
72
+ an argument.
73
+
74
+ # Returns array of Post objects.
75
+ my_search_results = Post.with_query('my search query')
76
+
77
+ # Chain it with any number of ActiveRecord methods and named_scopes.
78
+ my_search_results = Post.public.with_query('my search query').find(:all, :limit => 10) # return the first 10 matches which are public.
79
+
80
+
81
+ === Query Options
82
+
83
+ The following query operators are supported:
84
+
85
+ * AND:: This is the default option. 'cat dog' will find records matching 'cat' AND 'dog'.
86
+ * NOT:: 'cat -dog' will find records matching 'cat' AND NOT 'dog'
87
+ * INCLUDE:: 'cat +me' will find records matching 'cat' and 'me', even if 'me' is smaller than the +min_word_size+
88
+ * "":: Quoted terms are matched as phrases. '"cat dog"' will find records matching the whole phrase. Quoted terms can be preceded by the NOT operator; 'cat -"big dog"' etc. Quoted terms can include words shorter than the +min_word_size+.
89
+
90
+ === Pagination
91
+
92
+ Since +with_query+ is a named scope, WillPaginate can be used in the normal
93
+ fashion.
94
+
95
+ @images = Image.with_query('girl').paginate(:page => 1, :per_page => 5)
96
+
97
+ === Further Configuration
98
+
99
+ A config block can be provided in your environment files or initializers.
100
+ Example showing defaults:
101
+
102
+ ActsAsIndexed.configure do |config|
103
+ config.index_file = [RAILS_ROOT,'index']
104
+ config.index_file_depth = 3
105
+ config.min_word_size = 3
106
+ end
107
+
108
+ A full rundown of the available configuration options can be found in
109
+ <tt>lib/acts_as_indexed/configuration.rb</tt>
110
+
111
+ == RDoc Documentation
112
+
113
+ To generate the RDoc documentation, run the <tt>rake rdoc</tt> task in the
114
+ acts_as_indexed plugin folder. Then point your web browser at
115
+ <tt>vendor/plugins/acts_as_indexed/rdoc/index.html</tt>.
116
+
117
+ Alternatively, you can view the rdoc documentation
118
+ online[http://rdoc.info/projects/dougal/acts_as_indexed/].
119
+
120
+ == Problems, Comments, Suggestions?
121
+
122
+ All of the above are most welcome. mailto:dougal.s@gmail.com
123
+
124
+
125
+ == Credits
126
+
127
+ Douglas F Shearer - http:douglasfshearer.com
128
+
129
+
130
+ == Future Releases
131
+
132
+ Future releases will be looking to add the following features:
133
+ * Optional html scrubbing during indexing.
134
+ * Ranking affected by field weightings.
135
+ * Support for DataMapper, Sequel and the various MongoDB ORMs.
136
+ * UTF-8 support. See the current solution here:
137
+ https://gist.github.com/193903bb4e0d6e5debe1
@@ -0,0 +1,50 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the acts_as_indexed plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the acts_as_indexed plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'ActsAsIndexed'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('CHANGELOG')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ namespace :rcov do
26
+ desc "Generate a coverage report in coverage/"
27
+ task :gen do
28
+ sh "rcov --output coverage test/*_test.rb"
29
+ end
30
+
31
+ desc "Remove generated coverage files."
32
+ task :clobber do
33
+ sh "rm -rdf coverage"
34
+ end
35
+ end
36
+
37
+ begin
38
+ require 'jeweler'
39
+ Jeweler::Tasks.new do |gemspec|
40
+ gemspec.name = "acts_as_indexed"
41
+ gemspec.summary = "Acts As Indexed is a plugin which provides a pain-free way to add fulltext search to your Ruby on Rails app"
42
+ gemspec.description = gemspec.summary
43
+ gemspec.email = "dougal.s@gmail.com"
44
+ gemspec.homepage = "http://github.com/dougal/acts_as_indexed"
45
+ gemspec.authors = ["Douglas F Shearer"]
46
+ end
47
+ Jeweler::GemcutterTasks.new
48
+ rescue LoadError
49
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
50
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.2
@@ -0,0 +1,67 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{acts_as_indexed}
8
+ s.version = "0.6.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Douglas F Shearer"]
12
+ s.date = %q{2010-06-11}
13
+ s.description = %q{Acts As Indexed is a plugin which provides a pain-free way to add fulltext search to your Ruby on Rails app}
14
+ s.email = %q{dougal.s@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "CHANGELOG",
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "acts_as_indexed.gemspec",
26
+ "lib/acts_as_indexed.rb",
27
+ "lib/acts_as_indexed/configuration.rb",
28
+ "lib/acts_as_indexed/search_atom.rb",
29
+ "lib/acts_as_indexed/search_index.rb",
30
+ "lib/will_paginate_search.rb",
31
+ "rails/init.rb",
32
+ "test/abstract_unit.rb",
33
+ "test/acts_as_indexed_test.rb",
34
+ "test/configuration_test.rb",
35
+ "test/database.yml",
36
+ "test/fixtures/post.rb",
37
+ "test/fixtures/posts.yml",
38
+ "test/schema.rb",
39
+ "test/search_atom_test.rb",
40
+ "test/search_index_test.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/dougal/acts_as_indexed}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.7}
46
+ s.summary = %q{Acts As Indexed is a plugin which provides a pain-free way to add fulltext search to your Ruby on Rails app}
47
+ s.test_files = [
48
+ "test/abstract_unit.rb",
49
+ "test/acts_as_indexed_test.rb",
50
+ "test/configuration_test.rb",
51
+ "test/fixtures/post.rb",
52
+ "test/schema.rb",
53
+ "test/search_atom_test.rb",
54
+ "test/search_index_test.rb"
55
+ ]
56
+
57
+ if s.respond_to? :specification_version then
58
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
62
+ else
63
+ end
64
+ else
65
+ end
66
+ end
67
+
@@ -0,0 +1,248 @@
1
+ # ActsAsIndexed
2
+ # Copyright (c) 2007 - 2010 Douglas F Shearer.
3
+ # http://douglasfshearer.com
4
+ # Distributed under the MIT license as included with this plugin.
5
+
6
+ require 'active_record'
7
+
8
+ require 'acts_as_indexed/configuration'
9
+ require 'acts_as_indexed/search_index'
10
+ require 'acts_as_indexed/search_atom'
11
+
12
+ module ActsAsIndexed #:nodoc:
13
+
14
+ # Holds the default configuration for acts_as_indexed.
15
+
16
+ @configuration = Configuration.new
17
+
18
+ # Returns the current configuration for acts_as_indexed.
19
+
20
+ def self.configuration
21
+ @configuration
22
+ end
23
+
24
+ # Call this method to modify defaults in your initializers.
25
+ #
26
+ # Example showing defaults:
27
+ # ActsAsIndexed.configure do |config|
28
+ # config.index_file = [Rails.root,'index']
29
+ # config.index_file_depth = 3
30
+ # config.min_word_size = 3
31
+ # end
32
+
33
+ def self.configure
34
+ self.configuration ||= Configuration.new
35
+ yield(configuration)
36
+ end
37
+
38
+ def self.included(mod)
39
+ mod.extend(ClassMethods)
40
+ end
41
+
42
+ module ClassMethods
43
+
44
+ # Declares a class as searchable.
45
+ #
46
+ # ====options:
47
+ # fields:: Names of fields to include in the index. Symbols pointing to
48
+ # instance methods of your model may also be given here.
49
+ # index_file_depth:: Tuning value for the index partitioning. Larger
50
+ # values result in quicker searches, but slower
51
+ # indexing. Default is 3.
52
+ # min_word_size:: Sets the minimum length for a word in a query. Words
53
+ # shorter than this value are ignored in searches
54
+ # unless preceded by the '+' operator. Default is 3.
55
+ # index_file:: Sets the location for the index. By default this is
56
+ # RAILS_ROOT/index. Specify as an array. Heroku, for
57
+ # example would use RAILS_ROOT/tmp/index, which would be
58
+ # set as [Rails.root,'tmp','index]
59
+
60
+ def acts_as_indexed(options = {})
61
+ class_eval do
62
+ extend ActsAsIndexed::SingletonMethods
63
+ end
64
+ include ActsAsIndexed::InstanceMethods
65
+
66
+ after_create :add_to_index
67
+ before_update :update_index
68
+ after_destroy :remove_from_index
69
+
70
+ # scope for Rails 3.x, named_scope for Rails 2.x.
71
+ if self.respond_to?(:where)
72
+ scope :with_query, lambda { |query| where("#{table_name}.id IN (?)", search_index(query, {}, {:ids_only => true})) }
73
+ else
74
+ named_scope :with_query, lambda { |query| { :conditions => ["#{table_name}.id IN (?)", search_index(query, {}, {:ids_only => true}) ] } }
75
+ end
76
+
77
+ cattr_accessor :aai_config, :aai_fields
78
+
79
+ self.aai_fields = options.delete(:fields)
80
+ raise(ArgumentError, 'no fields specified') if self.aai_fields.nil? || self.aai_fields.empty?
81
+
82
+ self.aai_config = ActsAsIndexed.configuration.dup
83
+ options.each do |k, v|
84
+ self.aai_config.send("#{k}=", v)
85
+ end
86
+ self.aai_config.index_file += [Rails.env, self.name]
87
+ end
88
+
89
+ # Adds the passed +record+ to the index. Index is built if it does not already exist. Clears the query cache.
90
+
91
+ def index_add(record)
92
+ build_index if !File.exists?(File.join(aai_config.index_file))
93
+ index = SearchIndex.new(aai_config.index_file, aai_config.index_file_depth, aai_fields, aai_config.min_word_size)
94
+ index.add_record(record)
95
+ index.save
96
+ @query_cache = {}
97
+ true
98
+ end
99
+
100
+ # Removes the passed +record+ from the index. Clears the query cache.
101
+
102
+ def index_remove(record)
103
+ index = SearchIndex.new(aai_config.index_file, aai_config.index_file_depth, aai_fields, aai_config.min_word_size)
104
+ # record won't be in index if it doesn't exist. Just return true.
105
+ return true if !index.exists?
106
+ index.remove_record(record)
107
+ index.save
108
+ @query_cache = {}
109
+ true
110
+ end
111
+
112
+ # Updates the index.
113
+ # 1. Removes the previous version of the record from the index
114
+ # 2. Adds the new version to the index.
115
+
116
+ def index_update(record)
117
+ build_index if !File.exists?(File.join(aai_config.index_file))
118
+ index = SearchIndex.new(aai_config.index_file, aai_config.index_file_depth, aai_fields, aai_config.min_word_size)
119
+ #index.remove_record(find(record.id))
120
+ #index.add_record(record)
121
+ index.update_record(record,find(record.id))
122
+ index.save
123
+ @query_cache = {}
124
+ true
125
+ end
126
+
127
+ # Finds instances matching the terms passed in +query+. Terms are ANDed by
128
+ # default. Returns an array of model instances or, if +ids_only+ is
129
+ # true, an array of integer IDs.
130
+ #
131
+ # Keeps a cache of matched IDs for the current session to speed up
132
+ # multiple identical searches.
133
+ #
134
+ # ====find_options
135
+ # Same as ActiveRecord#find options hash. An :order key will override
136
+ # the relevance ranking
137
+ #
138
+ # ====options
139
+ # ids_only:: Method returns an array of integer IDs when set to true.
140
+ # no_query_cache:: Turns off the query cache when set to true. Useful for testing.
141
+
142
+ def search_index(query, find_options={}, options={})
143
+ # Clear the query cache off if the key is set.
144
+ @query_cache = {} if (options.has_key?('no_query_cache') || options[:no_query_cache])
145
+ if !@query_cache || !@query_cache[query]
146
+ logger.debug('Query not in cache, running search.')
147
+ build_index if !File.exists?(File.join(aai_config.index_file))
148
+ index = SearchIndex.new(aai_config.index_file, aai_config.index_file_depth, aai_fields, aai_config.min_word_size)
149
+ @query_cache = {} if !@query_cache
150
+ @query_cache[query] = index.search(query)
151
+ else
152
+ logger.debug('Query held in cache.')
153
+ end
154
+ return @query_cache[query].sort.reverse.map(&:first) if options[:ids_only] || @query_cache[query].empty?
155
+
156
+ # slice up the results by offset and limit
157
+ offset = find_options[:offset] || 0
158
+ limit = find_options.include?(:limit) ? find_options[:limit] : @query_cache[query].size
159
+ part_query = @query_cache[query].sort.reverse.slice(offset,limit).map(&:first)
160
+
161
+ # Set these to nil as we are dealing with the pagination by setting
162
+ # exactly what records we want.
163
+ find_options[:offset] = nil
164
+ find_options[:limit] = nil
165
+
166
+ with_scope :find => find_options do
167
+ # Doing the find like this eliminates the possibility of errors occuring
168
+ # on either missing records (out-of-sync) or an empty results array.
169
+ records = find(:all, :conditions => [ "#{table_name}.id IN (?)", part_query])
170
+
171
+ if find_options.include?(:order)
172
+ records # Just return the records without ranking them.
173
+ else
174
+ # Results come back in random order from SQL, so order again.
175
+ ranked_records = {}
176
+ records.each do |r|
177
+ ranked_records[r] = @query_cache[query][r.id]
178
+ end
179
+
180
+ ranked_records.to_a.sort_by{|a| a.last }.reverse.map(&:first)
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+ private
187
+
188
+ # Builds an index from scratch for the current model class.
189
+ def build_index
190
+ increment = 500
191
+ offset = 0
192
+ while (records = find(:all, :limit => increment, :offset => offset)).size > 0
193
+ #p "offset is #{offset}, increment is #{increment}"
194
+ index = SearchIndex.new(aai_config.index_file, aai_config.index_file_depth, aai_fields, aai_config.min_word_size)
195
+ offset += increment
196
+ index.add_records(records)
197
+ index.save
198
+ end
199
+ end
200
+
201
+ end
202
+
203
+ # Adds model class singleton methods.
204
+ module SingletonMethods
205
+
206
+ # DEPRECATED. Use +with_query+ scope instead.
207
+ # Finds instances matching the terms passed in +query+.
208
+ #
209
+ # See ActsAsIndexed::ClassMethods#search_index.
210
+ def find_with_index(query='', find_options = {}, options = {})
211
+ warn "[DEPRECATION] `find_with_index` is deprecated and will be removed in a later release. Use `with_query(query)` instead."
212
+ search_index(query, find_options, options)
213
+ end
214
+
215
+ end
216
+
217
+ # Adds model class instance methods.
218
+ # Methods are called automatically by ActiveRecord on +save+, +destroy+,
219
+ # and +update+ of model instances.
220
+ module InstanceMethods
221
+
222
+ # Adds the current model instance to index.
223
+ # Called by ActiveRecord on +save+.
224
+ def add_to_index
225
+ self.class.index_add(self)
226
+ end
227
+
228
+ # Removes the current model instance to index.
229
+ # Called by ActiveRecord on +destroy+.
230
+ def remove_from_index
231
+ self.class.index_remove(self)
232
+ end
233
+
234
+ # Updates current model instance index.
235
+ # Called by ActiveRecord on +update+.
236
+ def update_index
237
+ self.class.index_update(self)
238
+ end
239
+ end
240
+
241
+ end
242
+
243
+ # reopen ActiveRecord and include all the above to make
244
+ # them available to all our models if they want it
245
+
246
+ ActiveRecord::Base.class_eval do
247
+ include ActsAsIndexed
248
+ end