act_methods.rb
6.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
module ActsAsFerret #:nodoc:
# This module defines the acts_as_ferret method and is included into
# ActiveRecord::Base
module ActMethods
def reloadable?; false end
# declares a class as ferret-searchable.
#
# ====options:
# fields:: names all fields to include in the index. If not given,
# all attributes of the class will be indexed. You may also give
# symbols pointing to instance methods of your model here, i.e.
# to retrieve and index data from a related model.
#
# additional_fields:: names fields to include in the index, in addition
# to those derived from the db scheme. use if you want
# to add custom fields derived from methods to the db
# fields (which will be picked by aaf). This option will
# be ignored when the fields option is given, in that
# case additional fields get specified there.
#
# if:: Can be set to a block that will be called with the record in question
# to determine if it should be indexed or not.
#
# index_dir:: declares the directory where to put the index for this class.
# The default is RAILS_ROOT/index/RAILS_ENV/CLASSNAME.
# The index directory will be created if it doesn't exist.
#
# reindex_batch_size:: reindexing is done in batches of this size, default is 1000
# mysql_fast_batches:: set this to false to disable the faster mysql batching
# algorithm if this model uses a non-integer primary key named
# 'id' on MySQL.
#
# ferret:: Hash of Options that directly influence the way the Ferret engine works. You
# can use most of the options the Ferret::I class accepts here, too. Among the
# more useful are:
#
# or_default:: whether query terms are required by
# default (the default, false), or not (true)
#
# analyzer:: the analyzer to use for query parsing (default: nil,
# which means the ferret StandardAnalyzer gets used)
#
# default_field:: use to set one or more fields that are searched for query terms
# that don't have an explicit field list. This list should *not*
# contain any untokenized fields. If it does, you're asking
# for trouble (i.e. not getting results for queries having
# stop words in them). Aaf by default initializes the default field
# list to contain all tokenized fields. If you use :single_index => true,
# you really should set this option specifying your default field
# list (which should be equal in all your classes sharing the index).
# Otherwise you might get incorrect search results and you won't get
# any lazy loading of stored field data.
#
# For downwards compatibility reasons you can also specify the Ferret options in the
# last Hash argument.
def acts_as_ferret(options={})
extend ClassMethods
include InstanceMethods
include MoreLikeThis::InstanceMethods
if options[:rdig]
cattr_accessor :rdig_configuration
self.rdig_configuration = options[:rdig]
require 'rdig_adapter'
include ActsAsFerret::RdigAdapter
end
unless included_modules.include?(ActsAsFerret::WithoutAR)
# set up AR hooks
after_create :ferret_create
after_update :ferret_update
after_destroy :ferret_destroy
end
cattr_accessor :aaf_configuration
# apply default config for rdig based models
if options[:rdig]
options[:fields] ||= { :title => { :boost => 3, :store => :yes },
:content => { :store => :yes } }
end
# name of this index
index_name = options.delete(:index) || self.name.underscore
index = ActsAsFerret::register_class_with_index(self, index_name, options)
self.aaf_configuration = index.index_definition.dup
logger.debug "configured index for class #{self.name}:\n#{aaf_configuration.inspect}"
# update our copy of the global index config with options local to this class
aaf_configuration[:class_name] ||= self.name
aaf_configuration[:if] ||= options[:if]
# add methods for retrieving field values
add_fields options[:fields]
add_fields options[:additional_fields]
add_fields aaf_configuration[:fields]
add_fields aaf_configuration[:additional_fields]
# not good at class level, index might get initialized too early
#if options[:remote]
# aaf_index.ensure_index_exists
#end
end
protected
# helper to defines a method which adds the given field to a ferret
# document instance
def define_to_field_method(field, options = {})
method_name = "#{field}_to_ferret"
return if instance_methods.include?(method_name) # already defined
aaf_configuration[:defined_fields] ||= {}
aaf_configuration[:defined_fields][field] = options
dynamic_boost = options[:boost] if options[:boost].is_a?(Symbol)
via = options[:via] || field
define_method(method_name.to_sym) do
val = begin
content_for_field_name(field, via, dynamic_boost)
rescue
logger.warn("Error retrieving value for field #{field}: #{$!}")
''
end
logger.debug("Adding field #{field} with value '#{val}' to index")
val
end
end
def add_fields(field_config)
# TODO
#field_config.each do |*args|
# define_to_field_method *args
#end
if field_config.is_a? Hash
field_config.each_pair do |field, options|
define_to_field_method field, options
end
elsif field_config.respond_to?(:each)
field_config.each do |field|
define_to_field_method field
end
end
end
end
end