Module: ScopedSearch::ClassMethods

Defined in:
lib/scoped_search.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(base) ⇒ Object

:nodoc:



5
6
7
8
9
# File 'lib/scoped_search.rb', line 5

def self.extended(base) # :nodoc:
  require 'scoped_search/reg_tokens'
  require 'scoped_search/query_language_parser'
  require 'scoped_search/query_conditions_builder'
end

Instance Method Details

#build_scoped_search_conditions(search_string) ⇒ Object

Build a hash that is used for the named_scope search_for. This function will split the search_string into keywords, and search for all the keywords in the fields that were provided to searchable_on.

search_string

The search string to parse.



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
# File 'lib/scoped_search.rb', line 75

def build_scoped_search_conditions(search_string)    
  if search_string.nil? || search_string.strip.blank?
    return {:conditions => nil}
  else        
    query_fields = {}
    self.scoped_search_fields.each do |field| 
      field_name = connection.quote_table_name(table_name) + "." + connection.quote_column_name(field)
      query_fields[field_name] = self.columns_hash[field.to_s].type
    end
    
    assoc_model_indx = 0
    assoc_fields_indx = 1
    assoc_models_to_include = []
    self.scoped_search_assoc_groupings.each do |group|  
      assoc_models_to_include << group[assoc_model_indx]
      group[assoc_fields_indx].each do |group_field|
        field_name = connection.quote_table_name(group[assoc_model_indx].to_s.pluralize) + "." + connection.quote_column_name(group_field)
        query_fields[field_name] = self.reflections[group[assoc_model_indx]].klass.columns_hash[group_field.to_s].type
      end
    end
    
    search_conditions = QueryLanguageParser.parse(search_string) 
    conditions = QueryConditionsBuilder.build_query(search_conditions, query_fields) 
 
    retVal = {:conditions => conditions}
    retVal[:include] = assoc_models_to_include unless assoc_models_to_include.empty?

    return retVal
  end
end

#searchable_on(*fields) ⇒ Object

Creates a named scope in the class it was called upon.

fields

The fields to search on.



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
# File 'lib/scoped_search.rb', line 14

def searchable_on(*fields)
  # Make sure that the table to be searched actually exists
  if self.table_exists?
    
    # Get a collection of fields to be searched on.
    if fields.first.class.to_s == 'Hash'
      if fields.first.has_key?(:only)
        # only search on these fields.
        fields = fields.first[:only]
      elsif fields.first.has_key?(:except)
        # Get all the fields and remove any that are in the -except- list.
        fields = self.column_names.collect { |column| fields.first[:except].include?(column.to_sym) ? nil : column.to_sym }.compact
      end
    end
    
    # Get an array of associate modules.
    assoc_models = self.reflections.collect { |key,value| key }
    
    # Subtract out the fields to be searched on that are part of *this* model.
    # Any thing left will be associate module fields to be searched on.
    assoc_fields = fields - self.column_names.collect { |column| column.to_sym }
    
    # Subtraced out the associated fields from the fields so that you are only left
    # with fields in *this* model.
    fields -= assoc_fields
    
    # Loop through each of the associate models and group accordingly each
    # associate model field to search.  Assuming the following relations:
    # has_many :clients
    # has_many :notes,
    # belongs_to :user_type 
    # assoc_groupings will look like
    # assoc_groupings = {:clients => [:first_name, :last_name],
    #                    :notes => [:descr],
    #                    :user_type => [:identifier]}
    assoc_groupings = {}
    assoc_models.each do |assoc_model|
      assoc_groupings[assoc_model] = []
    	assoc_fields.each do |assoc_field|
    	  unless assoc_field.to_s.match(/^#{assoc_model.to_s}_/).nil?
          assoc_groupings[assoc_model] << assoc_field.to_s.sub(/^#{assoc_model.to_s}_/, '').to_sym 
        end
      end
    end

    # If a grouping does not contain any fields to be searched on then remove it.
    assoc_groupings = assoc_groupings.delete_if {|group, field_group| field_group.empty?}
    
    # Set the appropriate class attributes. 
    self.cattr_accessor :scoped_search_fields, :scoped_search_assoc_groupings
    self.scoped_search_fields = fields
    self.scoped_search_assoc_groupings = assoc_groupings
    self.named_scope :search_for, lambda { |keywords| self.build_scoped_search_conditions(keywords) }
  end
end