1 module ActsAsFerret #:nodoc:
4 include ResultAttributes
6 # Returns an array of strings with the matches highlighted. The +query+ can
7 # either be a String or a Ferret::Search::Query object.
11 # field:: field to take the content from. This field has
12 # to have it's content stored in the index
13 # (:store => :yes in your call to aaf). If not
14 # given, all stored fields are searched, and the
15 # highlighted content found in all of them is returned.
16 # set :highlight => :no in the field options to
17 # avoid highlighting of contents from a :stored field.
18 # excerpt_length:: Default: 150. Length of excerpt to show. Highlighted
19 # terms will be in the centre of the excerpt.
20 # num_excerpts:: Default: 2. Number of excerpts to return.
21 # pre_tag:: Default: "<em>". Tag to place to the left of the
23 # post_tag:: Default: "</em>". This tag should close the
25 # ellipsis:: Default: "...". This is the string that is appended
26 # at the beginning and end of excerpts (unless the
27 # excerpt hits the start or end of the field. You'll
28 # probably want to change this to a Unicode elipsis
30 def highlight(query, options = {})
31 self.class.aaf_index.highlight(id, self.class.name, query, options)
34 # re-eneable ferret indexing for this instance after a call to #disable_ferret
36 @ferret_disabled = nil
38 alias ferret_enable enable_ferret # compatibility
40 # returns true if ferret indexing is enabled for this record.
42 # The optional is_bulk_index parameter will be true if the method is called
43 # by rebuild_index or bulk_index, and false otherwise.
45 # If is_bulk_index is true, the class level ferret_enabled state will be
46 # ignored by this method (per-instance ferret_enabled checks however will
47 # take place, so if you override this method to forbid indexing of certain
48 # records you're still safe).
49 def ferret_enabled?(is_bulk_index = false)
50 @ferret_disabled.nil? && (is_bulk_index || self.class.ferret_enabled?)
53 # Disable Ferret for this record for a specified amount of time. ::once will
54 # disable Ferret for the next call to #save (this is the default), ::always
55 # will do so for all subsequent calls.
57 # Note that this will turn off only the create and update hooks, but not the
58 # destroy hook. I think that's reasonable, if you think the opposite, please
61 # To manually trigger reindexing of a record after you're finished modifying
62 # it, you can call #ferret_update directly instead of #save (remember to
63 # enable ferret again before).
65 # When given a block, this will be executed without any ferret indexing of
66 # this object taking place. The optional argument in this case can be used
67 # to indicate if the object should be indexed after executing the block
68 # (::index_when_finished). Automatic Ferret indexing of this object will be
69 # turned on after the block has been executed. If passed ::index_when_true,
70 # the index will only be updated if the block evaluated not to false or nil.
72 def disable_ferret(option = :once)
74 @ferret_disabled = :always
77 ferret_update if option == :index_when_finished || (option == :index_when_true && result)
79 elsif [:once, :always].include?(option)
80 @ferret_disabled = option
82 raise ArgumentError.new("Invalid Argument #{option}")
89 logger.debug "ferret_create/update: #{self.class.name} : #{self.id}"
90 self.class.aaf_index << self
92 ferret_enable if @ferret_disabled == :once
94 true # signal success to AR
96 alias :ferret_update :ferret_create
101 logger.debug "ferret_destroy: #{self.class.name} : #{self.id}"
103 self.class.aaf_index.remove self.id, self.class.name
105 logger.warn("Could not find indexed value for this object: #{$!}\n#{$!.backtrace}")
107 true # signal success to AR
110 # turn this instance into a ferret document (which basically is a hash of
111 # fieldname => value pairs)
113 logger.debug "creating doc for class: #{self.class.name}, id: #{self.id}"
114 returning Ferret::Document.new do |doc|
115 # store the id of each item
118 # store the class name if configured to do so
119 doc[:class_name] = self.class.name if aaf_configuration[:store_class_name]
121 # iterate through the fields and add them to the document
122 aaf_configuration[:ferret_fields].each_pair do |field, config|
123 doc[field] = self.send("#{field}_to_ferret") unless config[:ignore]
125 if aaf_configuration[:boost]
126 if self.respond_to?(aaf_configuration[:boost])
127 boost = self.send aaf_configuration[:boost]
128 doc.boost = boost.to_i if boost
130 logger.error "boost option should point to an instance method: #{aaf_configuration[:boost]}"
137 self.class.aaf_index.document_number(id, self.class.name)
141 self.class.aaf_index.query_for_record(id, self.class.name)
144 def content_for_field_name(field, dynamic_boost = nil)
145 field_data = self[field] || self.instance_variable_get("@#{field.to_s}".to_sym) || self.send(field.to_sym)
146 if (dynamic_boost && boost_value = self.send(dynamic_boost))
147 field_data = Ferret::Field.new(field_data)
148 field_data.boost = boost_value.to_i