module SearchMe::Search

Public Instance Methods

advanced_search_block_for?(type, attribute) click to toggle source
# File lib/search_me/search.rb, line 255
def advanced_search_block_for?(type, attribute)
  !advanced_search_blocks[type].blank? && 
    !advanced_search_blocks[type][attribute].blank?
end
advanced_search_blocks() click to toggle source
# File lib/search_me/search.rb, line 7
def advanced_search_blocks
  @advanced_search_blocks ||= default_hash(:never_a_key_like_this)
end
advanced_search_reflection_group(type, search_terms, &block) click to toggle source
# File lib/search_me/search.rb, line 208
def advanced_search_reflection_group(type, search_terms, &block)
  map_reflection_group(type, block) do |attributes,klass,reflection|
    attributes.map { |attribute|
      name = reflection.name
      term = search_terms[name][attribute]
      if advanced_search_block_for?(name, attribute)
        call_advanced_search_block_for(name, attribute, term)
      else
        klass.simple_search_where_condition(attribute, term)
      end
    }
  end
end
call_advanced_search_block_for(type, attribute, term) click to toggle source
# File lib/search_me/search.rb, line 260
def call_advanced_search_block_for(type, attribute, term)
  advanced_search_blocks[type][attribute].call(term)
end
constant_for(name) click to toggle source
# File lib/search_me/search.rb, line 287
def constant_for(name)
  name.to_s.camelize.singularize.constantize
end
default_hash(flat_key = :simple) click to toggle source
# File lib/search_me/search.rb, line 11
def default_hash(flat_key = :simple)
  Hash.new { |h,k| 
    h[k] = (k == flat_key ? [] : Hash.new { |nh,nk| nh[nk] = [] })
  }
end
indifferent_reflections() click to toggle source
# File lib/search_me/search.rb, line 301
def indifferent_reflections
  ActiveSupport::HashWithIndifferentAccess.new(self.reflections)
end
join(array) click to toggle source
# File lib/search_me/search.rb, line 62
def join(array)
  array.delete_if { |condition| condition.blank? }.join(joiner)
end
joiner() click to toggle source
# File lib/search_me/search.rb, line 75
def joiner 
  @joiner ||= :or
  " #{@joiner.upcase} "
end
klass_for_reflection(reflection) click to toggle source
# File lib/search_me/search.rb, line 272
def klass_for_reflection(reflection)
  if name = reflection.options[:class_name]
    constant_for(name)
  else
    constant_for(reflection.name)
  end
end
map_reflection_group(type, outer_block) { |attributes,klass,reflection| ... } click to toggle source
# File lib/search_me/search.rb, line 181
def map_reflection_group(type, outer_block)
  cond = @this_search_attributes[type].map {|reflection, attributes|
    reflection = indifferent_reflections[reflection]
    klass      = klass_for_reflection(reflection)

    reflection_condition = join(yield(attributes,klass,reflection))
      
    search_result = klass.where(reflection_condition)

    outer_block.call(reflection, search_result)
  }
  join(cond)
end
name_for(constant, options = {}) click to toggle source
# File lib/search_me/search.rb, line 280
def name_for(constant, options = {})
  plural = options.fetch(:plural) { false }
  name   = constant.to_s.underscore
  name   = name.singularize unless plural
  name
end
object_ids(objects, column = nil) click to toggle source
# File lib/search_me/search.rb, line 264
def object_ids(objects, column = nil)
  (column ? objects.map(&column.to_sym) : objects.ids) << -5318008 
end
reflection_search_condition(term) click to toggle source
# File lib/search_me/search.rb, line 138
def reflection_search_condition(term)
  macro_groups = search_attributes
  @this_search_attributes = macro_groups

  condition = macro_groups.keys.map { |type|
    case type
    when :belongs_to
      self.search_reflection_group(type, term) { |reflection, objs|
        "#{reflection.name}_id IN (#{object_ids(objs).join(',')})"
      }
    when :has_many
      self.search_reflection_group(type, term) { |reflection, objs|
        f_key = reflection.options
          .fetch(:foreign_key) { "#{self.to_s.underscore}_id" }

        "id IN (#{object_ids(objs, f_key).join(',')})"
      }
    when :has_one
      self.search_reflection_group(type, term) { |reflection, objs|
        f_key = "#{name_for(reflection.active_record.name)}_id"

        "id IN (#{object_ids(objs, f_key).join(',')})"
      }
    when :has_many_through
      warn 'WARNING: has_many_through in development'
      self.search_reflection_group(type, term) { |reflection,objs|
        f_key = "#{name_for(reflection.name)}_id"
        self_f_key = "#{name_for(self)}_id"
        related = through_klass_for_reflection(reflection)
          .where(f_key => objs.ids)

        "id IN (#{object_ids(related, self_f_key).join(',')})"
      }
    end
  }
  join(condition)
end
sanitize_params!(params) click to toggle source
# File lib/search_me/search.rb, line 291
def sanitize_params!(params)
  params.to_hash.symbolize_keys!.each { |k,v| 
    if v.is_a?(Hash)
      params[k] = v = v.to_hash
      sanitize_params!(v) and v.symbolize_keys!
    end
    params.delete(k) if v.blank? && !(v == false)
  }
end
search_attributes() click to toggle source
# File lib/search_me/search.rb, line 3
def search_attributes 
  @search_attributes ||= default_hash
end
search_attributes_hash!(attributes, type, hash = default_hash) click to toggle source
# File lib/search_me/search.rb, line 35
def search_attributes_hash!(attributes, type, hash = default_hash)
  if type == :simple
    hash[:simple] += attributes
    hash[:simple] = hash[:simple].uniq
  else
    reflection  = indifferent_reflections[type]
    macro       = reflection.macro
    klass       = klass_for_reflection(reflection)

    if macro == :has_many
      macro = :has_many_through if reflection.options[:through]
    end

    hash[macro][type] += attributes
    hash[macro][type] = hash[macro][type].uniq

    unless klass.kind_of?(SearchMe::Search)
      klass.extend(SearchMe::Search)
    end
  end
  hash = sanitize_params!(hash)
end
search_me(attribute, term) click to toggle source
# File lib/search_me/search.rb, line 58
def search_me(attribute, term)
  self.where(simple_search_where_condition(attribute, term))
end
search_reflection_group(type, term, &block) click to toggle source
# File lib/search_me/search.rb, line 195
def search_reflection_group(type, term, &block)
  map_reflection_group(type, block) do |attributes,klass,reflection|
    attributes.map { |attribute|
      name = reflection.name
      if advanced_search_block_for?(name, attribute)
        call_advanced_search_block_for(name, attribute, term)
      else
        klass.simple_search_where_condition(attribute, term)
      end
    }
  end
end
simple_search_condition(term) click to toggle source
# File lib/search_me/search.rb, line 222
def simple_search_condition(term)
  condition = search_attributes[:simple].map { |attribute|
    simple_search_where_condition(attribute, term)
  }
  join(condition)
end
simple_search_where_condition(attribute, term) click to toggle source
# File lib/search_me/search.rb, line 233
def simple_search_where_condition(attribute, term)
  table_column = "#{self.table_name}.#{attribute}"
  column = self.columns.find { |col| col.name == attribute.to_s }

  case column.type
  when :string, :integer, :text, :float, :decimal
    "CAST(#{table_column} AS CHAR) LIKE '%#{term}%'"
  when :boolean
    term = {
      true => "= 't'", false => "= 'f'", nil => 'IS NULL',
      1 => "= 't'", 0 => "= 'f'", '1' => "= 't'", '0' => "= 'f'"
    }.fetch(term) {
      good_args = term.keys.map(:inspect).join(',')
      error = "boolean column term must be #{good_args}"
      raise ArgumentError, error
    } 
    "#{table_column} #{term}"
  else
    warn "#{column.type} type is not supported by SearchMe::Search"
  end
end
through_klass_for_reflection(reflection) click to toggle source
# File lib/search_me/search.rb, line 268
def through_klass_for_reflection(reflection)
  constant_for(reflection.options[:through])
end