To edit pages or tickets please login with username/password: aaf/aaf

Changeset 92

Show
Ignore:
Timestamp:
09/09/06 17:04:18 (2 years ago)
Author:
jk
Message:

r1104@monsoon: jk | 2006-09-09 14:51:07 +0200
further separating into files

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/plugin/acts_as_ferret/init.rb

    r61 r92  
     1# Copyright (c) 2006 Kasper Weibel Nielsen-Refs, Thomas Lockney, Jens KrÀmer 
     2# 
     3# Permission is hereby granted, free of charge, to any person obtaining a copy 
     4# of this software and associated documentation files (the "Software"), to deal 
     5# in the Software without restriction, including without limitation the rights 
     6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
     7# copies of the Software, and to permit persons to whom the Software is 
     8# furnished to do so, subject to the following conditions: 
     9# 
     10# The above copyright notice and this permission notice shall be included in all 
     11# copies or substantial portions of the Software. 
     12# 
     13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
     14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
     15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
     16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
     17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
     18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
     19# SOFTWARE. 
     20 
     21require 'active_record' 
     22require 'set' 
     23 
    124require 'ferret' 
    2 #require 'rferret' 
    325 
    4 require 'multi_index' 
    526require 'acts_as_ferret' 
    627 
  • trunk/plugin/acts_as_ferret/lib/acts_as_ferret.rb

    r91 r92  
    1919# SOFTWARE. 
    2020 
    21 require 'active_record' 
    22 require 'set' 
     21require 'multi_index' 
     22require 'more_like_this' 
     23require 'class_methods' 
     24require 'instance_methods' 
    2325 
    2426# 0.10 problems 
     
    2628# IndexReader#latest? segfaults when used on multiple indexes 
    2729# :offset and :limit get ignored by search_each 
    28 # query_parser ignores or_default 
    2930 
    30 # Yet another Ferret Mixin. 
     31# The Rails ActiveRecord Ferret Mixin. 
    3132# 
    3233# This mixin adds full text search capabilities to any Rails model. 
    3334# 
    34 # It is heavily based on the original acts_as_ferret plugin done by 
    35 # Kasper Weibel and a modified version done by Thomas Lockney, which  
    36 # both can be found on  
    37 # http://ferret.davebalmain.com/trac/wiki/FerretOnRails 
     35# The current version emerged from on the original acts_as_ferret plugin done by 
     36# Kasper Weibel and a modified version done by Thomas Lockney, which  both can be  
     37# found on the Ferret Wiki: http://ferret.davebalmain.com/trac/wiki/FerretOnRails. 
    3838# 
    39 # usage: 
     39# basic usage: 
    4040# include the following in your model class (specifiying the fields you want to get indexed): 
    4141# acts_as_ferret :fields => [ 'title', 'description' ] 
     
    5050# Authors:  
    5151# Kasper Weibel Nielsen-Refs (original author) 
    52 # Jens Kraemer <jk@jkraemer.net> 
     52# Jens Kraemer <jk@jkraemer.net> (active maintainer) 
    5353# 
    5454module FerretMixin 
     
    9292      end 
    9393 
    94       # declare the class level helper methods 
    95       # which will load the relevant instance methods defined below when invoked 
    96       module ClassMethods 
    97          
    98         # helper that defines a method that adds the given field to a lucene  
    99         # document instance 
    100         def define_to_field_method(field, options = {})          
    101           options = {  
    102             :store => :no,  
    103             :index => :yes,  
    104             :term_vector => :with_positions_offsets, 
    105             :boost => 1.0 }.update(options) 
    106           fields_for_ferret[field] = options 
    107           define_method("#{field}_to_ferret".to_sym) do 
    108             begin 
    109               val = content_for_field_name(field) 
    110             rescue 
    111               logger.warn("Error retrieving value for field #{field}: #{$!}") 
    112               val = '' 
    113             end 
    114             logger.debug("Adding field #{field} with value '#{val}' to index") 
    115             val 
    116           end 
    117         end 
    118  
    119         def add_fields(field_config) 
    120           if field_config.respond_to?(:each_pair) 
    121             field_config.each_pair do |key,val| 
    122               define_to_field_method(key,val)                   
    123             end 
    124           elsif field_config.respond_to?(:each) 
    125             field_config.each do |field|  
    126               define_to_field_method(field) 
    127             end                 
    128           end 
    129         end 
    130          
    131         def reloadable?; false end 
    132          
    133         @@ferret_indexes = Hash.new 
    134         def ferret_indexes; @@ferret_indexes end 
    135          
    136         @@multi_indexes = Hash.new 
    137         def multi_indexes; @@multi_indexes end 
    138          
    139         # declares a class as ferret-searchable.  
    140         # 
    141         # options are: 
    142         # 
    143         # fields:: names all fields to include in the index. If not given, 
    144         #   all attributes of the class will be indexed. You may also give 
    145         #   symbols pointing to instance methods of your model here, i.e.  
    146         #   to retrieve and index data from a related model.  
    147         # 
    148         # additional_fields:: names fields to include in the index, in addition  
    149         #   to those derived from the db scheme. use if you want to add 
    150         #   custom fields derived from methods to the db fields (which will be picked  
    151         #   by aaf). This option will be ignored when the fields option is given, in  
    152         #   that case additional fields get specified there. 
    153         # 
    154         # index_dir:: declares the directory where to put the index for this class. 
    155         #   The default is RAILS_ROOT/index/RAILS_ENV/CLASSNAME.  
    156         #   The index directory will be created if it doesn't exist. 
    157         # 
    158         # single_index:: set this to true to let this class use a Ferret 
    159         # index that is shared by all classes having :single_index set to true. 
    160         # :store_class_name is set to true implicitly, as well as index_dir, so  
    161         # don't bother setting these when using this option. the shared index 
    162         # will be located in index/<RAILS_ENV>/shared . 
    163         # 
    164         # store_class_name:: to make search across multiple models useful, set 
    165         # this to true. the model class name will be stored in a keyword field  
    166         # named class_name 
    167         # 
    168         # max_results:: number of results to retrieve for :num_docs => :all, 
    169         # default value is 1000 
    170         # 
    171         # ferret_options may be: 
    172         # or_default:: - whether query terms are required by 
    173         #   default (the default, false), or not (true) 
    174         #  
    175         # analyzer:: the analyzer to use for query parsing (default: nil, 
    176         #   wihch means the ferret StandardAnalyzer gets used) 
    177         # 
    178         def acts_as_ferret(options={}, ferret_options={}) 
    179           configuration = {  
    180             :index_dir => "#{FerretMixin::Acts::ARFerret::index_dir}/#{self.name.underscore}", 
    181             :store_class_name => false, 
    182             :single_index => false, 
    183             :max_results => 1000 
    184           } 
    185           ferret_configuration = { 
    186             :or_default => false,  
    187             :handle_parser_errors => true 
    188             #:max_clauses => 512, 
    189             #:default_field => '*', 
    190             #:analyzer => Ferret::Analysis::StandardAnalyzer.new, 
    191             # :wild_card_downcase => true 
    192           } 
    193           configuration.update(options) if options.is_a?(Hash) 
    194  
    195           # apply appropriate settings for shared index 
    196           if configuration[:single_index]  
    197             configuration[:index_dir] = "#{FerretMixin::Acts::ARFerret::index_dir}/shared"  
    198             configuration[:store_class_name] = true  
    199           end 
    200           ferret_configuration.update(ferret_options) if ferret_options.is_a?(Hash) 
    201           # these properties are somewhat vital to the plugin and shouldn't 
    202           # be overwritten by the user: 
    203           ferret_configuration.update( 
    204  
    205             :key               => (configuration[:single_index] ? [:id, :class_name] : :id), 
    206             :path              => configuration[:index_dir], 
    207             :auto_flush        => true, 
    208             :create_if_missing => true 
    209           ) 
    210            
    211           class_eval <<-EOV 
    212               include FerretMixin::Acts::ARFerret::InstanceMethods 
    213  
    214  
    215               after_create :ferret_create 
    216               after_update :ferret_update 
    217               after_destroy :ferret_destroy       
    218                
    219               cattr_accessor :fields_for_ferret    
    220               cattr_accessor :configuration 
    221               cattr_accessor :ferret_configuration 
    222                
    223               @@fields_for_ferret = Hash.new 
    224               @@configuration = configuration 
    225               @@ferret_configuration = ferret_configuration 
    226  
    227               if configuration[:fields] 
    228                 add_fields(configuration[:fields]) 
    229               else 
    230                 add_fields(self.new.attributes.keys.map { |k| k.to_sym }) 
    231                 add_fields(configuration[:additional_fields]) 
    232               end 
    233  
    234             EOV 
    235           FerretMixin::Acts::ARFerret::ensure_directory configuration[:index_dir] 
    236         end 
    237          
    238         def class_index_dir 
    239           configuration[:index_dir] 
    240         end 
    241          
    242         # rebuild the index from all data stored for this model. 
    243         # This is called automatically when no index exists yet. 
    244         # 
    245         # TODO: the automatic index initialization only works if  
    246         # every model class has it's  
    247         # own index, otherwise the index will get populated only 
    248         # with instances from the first model loaded 
    249         # 
    250         # When calling this method manually, you can give any additional  
    251         # model classes that should also go into this index as parameters.  
    252         # Useful when using the :single_index option. 
    253         # Note that attributes named the same in different models will share 
    254         # the same field options in the shared index. 
    255         def rebuild_index(*models) 
    256           models << self 
    257           # default attributes for fields 
    258           fi = Ferret::Index::FieldInfos.new(:store => :no,  
    259                                              :index => :yes,  
    260                                              :term_vector => :no, 
    261                                              :boost => 1.0) 
    262           # primary key 
    263           fi.add_field(:id, :store => :yes, :index => :untokenized)  
    264           # class_name 
    265           if configuration[:store_class_name] 
    266             fi.add_field(:class_name, :store => :yes, :index => :untokenized)  
    267           end 
    268           # collect field options from all models 
    269           fields = {} 
    270           models.each do |model| 
    271             fields.update(model.fields_for_ferret) 
    272           end 
    273           logger.debug("class #{self.name}: fields for index: #{fields.keys.join(',')}") 
    274           fields.each_pair do |field, options| 
    275             fi.add_field(field, { :store => :no,  
    276                                   :index => :yes }.update(options))  
    277           end 
    278           fi.create_index(ferret_configuration[:path]) 
    279  
    280           index = Ferret::Index::Index.new(ferret_configuration.dup.update(:auto_flush => false)) 
    281           batch_size = 1000 
    282           models.each do |model| 
    283             # index in batches of 1000 to limit memory consumption (fixes #24) 
    284             model.transaction do 
    285               0.step(model.count, batch_size) do |i| 
    286                 model.find(:all, :limit => batch_size, :offset => i).each do |rec| 
    287                   index << rec.to_doc 
    288                 end 
    289               end 
    290             end 
    291           end 
    292           logger.debug("Created Ferret index in: #{class_index_dir}") 
    293           index.flush 
    294           index.optimize 
    295           index.close 
    296         end                                                             
    297          
    298         # Retrieve the Ferret::Index::Index instance for this model class. 
    299         #  
    300         # Index instances are stored in a hash, using the index directory 
    301         # as the key. So model classes sharing a single index will share their 
    302         # Index object, too. 
    303         def ferret_index 
    304           ferret_indexes[class_index_dir] ||= create_index_instance 
    305         end  
    306          
    307         # creates a new Index::Index instance. Before that, a check is done 
    308         # to see if the index exists in the file system. If not, index rebuild 
    309         # from all model data retrieved by find(:all) is triggered. 
    310         def create_index_instance 
    311           rebuild_index unless File.file? "#{class_index_dir}/segments" 
    312           Ferret::Index::Index.new(ferret_configuration) 
    313         end 
    314          
    315         # Finds instances by contents. Terms are ANDed by default, can be circumvented  
    316         # by using OR between terms.  
    317         # options: 
    318         # :first_doc - first hit to retrieve (useful for paging) 
    319         # :num_docs - number of hits to retrieve, or :all to retrieve 
    320         # max_results results, which by default is 1000 and can be changed in 
    321         # the call to acts_as_ferret or on demand like this: 
    322         # Model.configuration[:max_results] = 1000000 
    323          # 
    324         # find_options is a hash passed on to active_record's find when 
    325         # retrieving the data from db, useful to i.e. prefetch relationships. 
    326         # 
    327         # this method returns a SearchResults instance, which really is an Array that has  
    328         # been decorated with a total_hits accessor that delivers the total 
    329         # number of hits (including those not fetched because of a low num_docs 
    330         # value). 
    331         def find_by_contents(q, options = {}, find_options = {}) 
    332           # handle shared index 
    333           return single_index_find_by_contents(q, options, find_options) if configuration[:single_index] 
    334           id_array = [] 
    335           id_positions = {} 
    336           total_hits = find_id_by_contents(q, options) do |model, id, score| 
    337             id_array << id 
    338             # store index of this id for later ordering of results 
    339             id_positions[id] = id_array.size 
    340           end 
    341           begin 
    342             # TODO: in case of STI AR will filter out hits from other  
    343             # classes for us, but this 
    344             # will lead to less results retrieved --> scoping of ferret query 
    345             # to self.class is still needed. 
    346             if id_array.empty? 
    347               result = [] 
    348             else 
    349               conditions = [ "#{self.table_name}.id in (?)", id_array ] 
    350               # combine our conditions with those given by user, if any 
    351               if find_options[:conditions] 
    352                 cust_opts = find_options[:conditions].dup 
    353                 conditions.first << " and " << cust_opts.shift 
    354                 conditions.concat(cust_opts) 
    355               end 
    356               result = self.find(:all,  
    357                                  find_options.merge(:conditions => conditions)) 
    358             end 
    359           rescue 
    360             logger.debug "REBUILD YOUR INDEX! One of the id's didn't have an associated record: #{id_array}" 
    361           end 
    362  
    363           # order results as they were found by ferret, unless an AR :order 
    364           # option was given 
    365           unless find_options[:order] 
    366             result.sort! { |a, b| id_positions[a.id] <=> id_positions[b.id] } 
    367           end 
    368            
    369           logger.debug "Query: #{q}\nResult id_array: #{id_array.inspect},\nresult: #{result}" 
    370           return SearchResults.new(result, total_hits) 
    371         end  
    372  
    373         # determine all field names in the shared index 
    374         def single_index_field_names(models) 
    375           @single_index_field_names ||= ( 
    376               searcher = Ferret::Search::Searcher.new(class_index_dir) 
    377               if searcher.reader.respond_to?(:get_field_names) 
    378                 (searcher.reader.send(:get_field_names) - ['id', 'class_name']).to_a 
    379               else 
    380                 puts <<-END 
    381   unable to retrieve field names for class #{self.name}, please  
    382   consider naming all indexed fields in your call to acts_as_ferret! 
    383                 END 
    384                 models.map { |m| m.content_columns.map { |col| col.name } }.flatten 
    385               end 
    386           ) 
    387  
    388         end 
    389          
    390         # weiter: checken ob ferret-bug, dass wir die queries so selber bauen 
    391         # muessen - liegt am downcasen des qparsers ? - gucken ob jetzt mit 
    392         # ferret geht (content_cols) und dave um zugriff auf qp bitten, oder 
    393         # auf reader 
    394         def single_index_find_by_contents(q, options = {}, find_options = {}) 
    395           result = [] 
    396  
    397           unless options[:models] == :all # search needs to be restricted by one or more class names 
    398             options[:models] ||= []  
    399             # add this class to the list of given models 
    400             options[:models] << self unless options[:models].include?(self) 
    401             # build query parser TODO: cache these somehow 
    402             original_query = q 
    403             if q.is_a? String 
    404               #class_clauses = [] 
    405               #options[:models].each do |model| 
    406               #  class_clauses << "class_name:#{model}" 
    407               #end 
    408               #q << " AND (#{class_clauses.join(' OR ')})" 
    409  
    410               qp = Ferret::QueryParser.new (ferret_configuration) 
    411               qp.fields = ferret_index.send(:reader).field_names 
    412               original_query = qp.parse(q) 
    413             end 
    414             #else 
    415             q = Ferret::Search::BooleanQuery.new 
    416             q.add_query(original_query, :must) 
    417             model_query = Ferret::Search::BooleanQuery.new 
    418             options[:models].each do |model| 
    419               model_query.add_query(Ferret::Search::TermQuery.new(:class_name, model.name), :should) 
    420             end 
    421             q.add_query(model_query, :must) 
    422             #end 
    423           end 
    424           #puts q.to_s 
    425           total_hits = find_id_by_contents(q, options) do |model, id, score| 
    426             result << Object.const_get(model).find(id, find_options.dup) 
    427           end 
    428           return SearchResults.new(result, total_hits) 
    429         end 
    430         protected :single_index_find_by_contents 
    431  
    432         # Finds instance model name, ids and scores by contents.  
    433         # Useful if you want to search across models 
    434         # Terms are ANDed by default, can be circumvented by using OR between terms. 
    435         # 
    436         # Example controller code (not tested): 
    437         # def multi_search(query) 
    438         #   result = [] 
    439         #   result << (Model1.find_id_by_contents query) 
    440         #   result << (Model2.find_id_by_contents query) 
    441         #   result << (Model3.find_id_by_contents query) 
    442         #   result.flatten! 
    443         #   result.sort! {|element| element[:score]} 
    444         #   # Figure out for yourself how to retreive and present the data from modelname and id  
    445         # end 
    446         # 
    447         # Note that the scores retrieved this way aren't normalized across 
    448         # indexes, so that the order of results after sorting by score will 
    449         # differ from the order you would get when running the same query 
    450         # on a single index containing all the data from Model1, Model2  
    451         # and Model 
    452         # 
    453         # options: 
    454         # :first_doc - first hit to retrieve (useful for paging) 
    455         # :num_docs - number of hits to retrieve, or :all to retrieve 
    456         # max_results results, which by default is 1000 and can be changed in 
    457         # the call to acts_as_ferret or on demand like this: 
    458         # Model.configuration[:max_results] = 1000000 
    459         # 
    460         # a block can be given too, it will be executed with every result: 
    461         # find_id_by_contents(q, options) do |model, id, score| 
    462         #    id_array << id 
    463         #    scores_by_id[id] = score  
    464         # end 
    465         # NOTE: in case a block is given, the total_hits value will be returned 
    466         # instead of the result list! 
    467         #  
    468         def find_id_by_contents(q, options = {}) 
    469           deprecated_options_support(options) 
    470           options[:limit] = configuration[:max_results] if options[:limit] == :all 
    471  
    472           result = [] 
    473           index = self.ferret_index 
    474           #hits = index.search(q, options) 
    475           #hits.each do |hit, score| 
    476           total_hits = index.search_each(q, options) do |hit, score| 
    477             # only collect result data if we intend to return it 
    478             doc = index[hit] 
    479             model = configuration[:store_class_name] ? doc[:class_name] : self.name 
    480             if block_given? 
    481               yield model, doc[:id].to_i, score 
    482             else 
    483               result << { :model => model, :id => doc[:id], :score => score } 
    484             end 
    485           end 
    486           logger.debug "id_score_model array: #{result.inspect}" 
    487           return block_given? ? total_hits : result 
    488         end 
    489          
    490         # requires the store_class_name option of acts_as_ferret to be true 
    491         # for all models queried this way. 
    492         # 
    493         # TODO: not optimal as each instance is fetched in a db call for it's 
    494         # own. 
    495         def multi_search(query, additional_models = [], options = {}) 
    496           result = [] 
    497           total_hits = id_multi_search(query, additional_models, options) do |model, id, score| 
    498             result << Object.const_get(model).find(id) 
    499           end 
    500           SearchResults.new(result, total_hits) 
    501         end 
    502          
    503         # returns an array of hashes, each containing :class_name, 
    504         # :id and :score for a hit. 
    505         # 
    506         # if a block is given, class_name, id and score of each hit will  
    507         # be yielded, and the total number of hits is returned. 
    508         # 
    509         def id_multi_search(query, additional_models = [], options = {}) 
    510           deprecated_options_support(options) 
    511           options[:limit] = configuration[:max_results] if options[:limit] == :all 
    512           additional_models << self 
    513           searcher = multi_index(additional_models) 
    514           result = [] 
    515           total_hits = searcher.search_each (query, options) do |hit, score| 
    516             doc = searcher[hit] 
    517             if block_given? 
    518               yield doc[:class_name], doc[:id].to_i, score 
    519             else 
    520               result << { :model => doc[:class_name], :id => doc[:id], :score => score } 
    521             end 
    522           end 
    523           return block_given? ? total_hits : result 
    524         end 
    525          
    526         # returns a MultiIndex instance operating on a MultiReader 
    527         def multi_index(model_classes) 
    528           model_classes.sort! { |a, b| a.name <=> b.name } 
    529           key = model_classes.inject("") { |s, clazz| s << clazz.name } 
    530           @@multi_indexes[key] ||= MultiIndex.new(model_classes, ferret_configuration) 
    531         end 
    532  
    533         def deprecated_options_support(options) 
    534           if options[:num_docs] 
    535             logger.warn ":num_docs is deprecated, use :limit instead!" 
    536             options[:limit] ||= options[:num_docs] 
    537           end 
    538           if options[:first_doc] 
    539             logger.warn ":first_doc is deprecated, use :offset instead!" 
    540             options[:offset] ||= options[:first_doc] 
    541           end 
    542         end 
    543       end 
    54494       
    545        
    546       module InstanceMethods 
    547         include MoreLikeThis 
    548          
    549         # re-eneable ferret indexing after a call to #disable_ferret 
    550         def ferret_enable; @ferret_disabled = nil end 
    551         
    552         # returns true if ferret indexing is enabled 
    553         def ferret_enabled?; @ferret_disabled.nil? end 
    554  
    555         # Disable Ferret for a specified amount of time. ::once will disable 
    556         # Ferret for the next call to #save (this is the default), ::always will  
    557         # do so for all subsequent calls. 
    558         # To manually trigger reindexing of a record, you can call #ferret_update  
    559         # directly.  
    560         # 
    561         # When given a block, this will be executed without any ferret indexing of  
    562         # this object taking place. The optional argument in this case can be used  
    563         # to indicate if the object should be indexed after executing the block 
    564         # (::index_when_finished). Automatic Ferret indexing of this object will be  
    565         # turned on after the block has been executed. 
    566         def disable_ferret(option = :once) 
    567           if block_given? 
    568             @ferret_disabled = :always 
    569             yield 
    570             ferret_enable 
    571             ferret_update if option == :index_when_finished 
    572           elsif [:once, :always].include?(option) 
    573             @ferret_disabled = option 
    574           else 
    575             raise ArgumentError.new("Invalid Argument #{option}") 
    576           end 
    577         end 
    578  
    579         # add to index 
    580         def ferret_create 
    581           if ferret_enabled? 
    582             logger.debug "ferret_create/update: #{self.class.name} : #{self.id}" 
    583             self.class.ferret_index << self.to_doc 
    584           else 
    585             ferret_enable if @ferret_disabled == :once 
    586           end 
    587           @ferret_enabled = true 
    588           true # signal success to AR 
    589         end 
    590         alias :ferret_update :ferret_create 
    591          
    592         # remove from index 
    593         def ferret_destroy 
    594           logger.debug "ferret_destroy: #{self.class.name} : #{self.id}" 
    595           begin 
    596             query = Ferret::Search::TermQuery.new(:id, self.id.to_s) 
    597             if self.class.configuration[:single_index] 
    598               bq = Ferret::Search::BooleanQuery.new 
    599               bq.add_query(query, :must) 
    600               bq.add_query(Ferret::Search::TermQuery.new(:class_name, self.class.name), :must) 
    601               query = bq 
    602             end 
    603             self.class.ferret_index.query_delete(query) 
    604           rescue 
    605             logger.warn("Could not find indexed value for this object: #{$!}") 
    606           end 
    607           true # signal success to AR 
    608         end 
    609          
    610         # convert instance to ferret document 
    611         def to_doc 
    612           logger.debug "creating doc for class: #{self.class.name}, id: #{self.id}" 
    613           # Churn through the complete Active Record and add it to the Ferret document 
    614           doc = Ferret::Document.new 
    615           # store the id of each item 
    616           doc[:id] = self.id 
    617  
    618           # store the class name if configured to do so 
    619           if configuration[:store_class_name] 
    620             doc[:class_name] = self.class.name 
    621           end 
    622           # iterate through the fields and add them to the document 
    623           #if fields_for_ferret 
    624             # have user defined fields 
    625           fields_for_ferret.each_pair do |field, config| 
    626             doc[field] = self.send("#{field}_to_ferret") unless config[:ignore] 
    627           end 
    628           #else 
    629             # take all fields 
    630             # TODO shouldn't be needed any more 
    631           #  puts "remove me!" 
    632           #  self.attributes.each_pair do |key,val| 
    633           #    unless key == :id 
    634           #      logger.debug "add field #{key} with value #{val}" 
    635           #      doc[key] = val.to_s 
    636           #    end 
    637            # end 
    638           #end 
    639           return doc 
    640         end 
    641  
    642         # BIG TODO: this file really gets too big. need to refactor a bit... 
    643         # maybe extract the more like this stuff, could be useful somewhere 
    644         # else, too... 
    645  
    646       end 
    64795       
    64896    end 

To edit pages or tickets please login with username/password: aaf/aaf