class ScopedSearch::Definition

The ScopedSearch definition class defines on what fields should be search in the model in what cases

A definition can be created by calling the scoped_search method on an ActiveRecord-based class, so you should not create an instance of this class yourself.

Constants

INTEGER_REGXP
NUMERICAL_REGXP

Attributes

default_order[RW]
klass[R]
profile[RW]

Public Class Methods

new(klass) click to toggle source

Initializes a ScopedSearch definition instance. This method will also setup a database adapter and create the :search_for named scope if it does not yet exist.

    # File lib/scoped_search/definition.rb
182 def initialize(klass)
183   @klass                 = klass
184   @fields                = {}
185   @unique_fields         = []
186   @profile_fields        = {:default => {}}
187   @profile_unique_fields = {:default => []}
188 
189   register_named_scope! unless klass.respond_to?(:search_for)
190   register_complete_for! unless klass.respond_to?(:complete_for)
191 end

Public Instance Methods

default_fields() click to toggle source

Returns a list of fields that should be searched on by default.

Every field will show up in this method's result, except for fields for which the only_explicit parameter is set to true.

    # File lib/scoped_search/definition.rb
275 def default_fields
276   unique_fields.reject { |field| field.only_explicit }
277 end
default_fields_for(value, operator = nil) click to toggle source

Returns a list of appropriate fields to search in given a search keyword and operator.

    # File lib/scoped_search/definition.rb
246 def default_fields_for(value, operator = nil)
247 
248   column_types  = []
249   column_types += [:string, :text]                if [nil, :like, :unlike, :ne, :eq].include?(operator)
250   column_types += [:double, :float, :decimal]     if value =~ NUMERICAL_REGXP
251   column_types += [:integer]                      if value =~ INTEGER_REGXP
252   column_types += [:datetime, :date, :timestamp]  if (parse_temporal(value))
253 
254   default_fields.select { |field| column_types.include?(field.type) && !field.set? }
255 end
define(*args) click to toggle source

Defines a new search field for this search definition.

    # File lib/scoped_search/definition.rb
280 def define(*args)
281   Field.new(self, *args)
282 end
define_field(name, field) click to toggle source
    # File lib/scoped_search/definition.rb
199 def define_field(name, field)
200   @profile ||= :default
201   @profile_fields[@profile] ||= {}
202   @profile_fields[@profile][name.to_sym] ||= field
203   @profile_unique_fields[@profile] ||= []
204   @profile_unique_fields[@profile] = (@profile_unique_fields[@profile] + [field]).uniq
205   field
206 end
field_by_name(name) click to toggle source

this method return definitions::field object from string

    # File lib/scoped_search/definition.rb
221 def field_by_name(name)
222   field = fields[name.to_sym] unless name.blank?
223   if field.nil?
224     dotted = name.to_s.split('.')[0]
225     field = fields[dotted.to_sym] unless dotted.blank?
226   end
227   field
228 end
fields() click to toggle source
    # File lib/scoped_search/definition.rb
208 def fields
209   @profile ||= :default
210   @profile_fields[@profile] ||= {}
211   super_definition ? super_definition.fields.merge(@profile_fields[@profile]) : @profile_fields[@profile]
212 end
operator_by_field_name(name) click to toggle source

this method is used by the syntax auto completer to suggest operators.

    # File lib/scoped_search/definition.rb
231 def operator_by_field_name(name)
232   field = field_by_name(name)
233   return [] if field.nil?
234   return field.operators                                      if field.operators
235   return ['= ', '!= ']                                        if field.set?
236   return ['= ', '> ', '< ', '<= ', '>= ','!= ', '^ ', '!^ ']  if field.numerical?
237   return ['= ', '!= ', '~ ', '!~ ', '^ ', '!^ ']              if field.textual?
238   return ['= ', '> ', '< ']                                   if field.temporal?
239   raise ScopedSearch::QueryNotSupported, "Unsupported type '#{field.type.inspect}')' for field '#{name}'. This can be a result of a search definition problem."
240 end
parse_temporal(value) click to toggle source

Try to parse a string as a datetime. Supported formats are Today, Yesterday, Sunday, '1 day ago', '2 hours ago', '3 months ago', '4 weeks from now', 'Jan 23, 2004' And many more formats that are documented in Ruby DateTime API Doc.

    # File lib/scoped_search/definition.rb
260 def parse_temporal(value)
261   return Date.current if value =~ /\btoday\b/i
262   return 1.day.ago.to_date if value =~ /\byesterday\b/i
263   return 1.day.from_now.to_date if value =~ /\btomorrow\b/i
264   return (eval($1.strip.gsub(/\s+/,'.').downcase)).to_datetime if value =~ /\A\s*(\d+\s+\b(?:hours?|minutes?)\b\s+\bago)\b\s*\z/i
265   return (eval($1.strip.gsub(/\s+/,'.').downcase)).to_date     if value =~ /\A\s*(\d+\s+\b(?:days?|weeks?|months?|years?)\b\s+\bago)\b\s*\z/i
266   return (eval($1.strip.gsub(/from\s+now/i,'from_now').gsub(/\s+/,'.').downcase)).to_datetime if value =~ /\A\s*(\d+\s+\b(?:hours?|minutes?)\b\s+\bfrom\s+now)\b\s*\z/i
267   return (eval($1.strip.gsub(/from\s+now/i,'from_now').gsub(/\s+/,'.').downcase)).to_date     if value =~ /\A\s*(\d+\s+\b(?:days?|weeks?|months?|years?)\b\s+\bfrom\s+now)\b\s*\z/i
268   DateTime.parse(value, true) rescue nil
269 end
reflection_by_name(klass, name) click to toggle source

Returns a reflection for a given klass and name

    # File lib/scoped_search/definition.rb
285 def reflection_by_name(klass, name)
286   return if name.nil?
287   klass.reflections[name.to_sym] || klass.reflections[name.to_s]
288 end
super_definition() click to toggle source
    # File lib/scoped_search/definition.rb
195 def super_definition
196   klass.superclass.try(:scoped_search_definition)
197 end
unique_fields() click to toggle source
    # File lib/scoped_search/definition.rb
214 def unique_fields
215   @profile ||= :default
216   @profile_unique_fields[@profile] ||= []
217   super_definition ? (super_definition.unique_fields + @profile_unique_fields[@profile]).uniq : @profile_unique_fields[@profile]
218 end

Protected Instance Methods

register_complete_for!() click to toggle source

Registers the complete_for method within the class that is used for searching.

    # File lib/scoped_search/definition.rb
312 def register_complete_for! # :nodoc
313   @klass.extend(ScopedSearch::AutoCompleteClassMethods)
314 end
register_named_scope!() click to toggle source

Registers the search_for named scope within the class that is used for searching.

    # File lib/scoped_search/definition.rb
293 def register_named_scope! # :nodoc
294   @klass.define_singleton_method(:search_for) do |query = '', options = {}|
295     # klass may be different to @klass if the scope is called on a subclass
296     klass = self
297     definition = klass.scoped_search_definition
298 
299     search_scope = klass.all
300     find_options = ScopedSearch::QueryBuilder.build_query(definition, query || '', options)
301     search_scope = search_scope.where(find_options[:conditions])   if find_options[:conditions]
302     search_scope = search_scope.includes(find_options[:include])   if find_options[:include]
303     search_scope = search_scope.joins(find_options[:joins])        if find_options[:joins]
304     search_scope = search_scope.reorder(find_options[:order])      if find_options[:order]
305     search_scope = search_scope.references(find_options[:include]) if find_options[:include]
306 
307     search_scope
308   end
309 end