class Filterer::Base

Attributes

meta[RW]
opts[RW]
params[RW]
results[RW]
sort[RW]

Public Class Methods

chain(params = {}, opts = {}) click to toggle source

@return [ActiveRecord::Association]

# File lib/filterer/base.rb, line 65
def chain(params = {}, opts = {})
  new(params, opts.merge(
    skip_ordering: true,
    skip_pagination: true
  )).results
end
filter(params = {}, opts = {}) click to toggle source

Public API @return [ActiveRecord::Association]

# File lib/filterer/base.rb, line 53
def filter(params = {}, opts = {})
  new(params, opts).results
end
filter_without_pagination(params = {}, opts = {}) click to toggle source

@return [ActiveRecord::Association]

# File lib/filterer/base.rb, line 58
def filter_without_pagination(params = {}, opts = {})
  new(params, opts.merge(
    skip_pagination: true
  )).results
end
new(params = {}, opts = {}) click to toggle source
# File lib/filterer/base.rb, line 73
def initialize(params = {}, opts = {})
  self.opts = opts
  self.params = defaults.merge(parse_strong_parameters(params)).
                  with_indifferent_access
  self.results = opts[:starting_query] || starting_query
  self.results = apply_default_filters || results
  add_params_to_query
  self.results = ordered_results unless opts[:skip_ordering]
  paginate_results unless opts[:skip_pagination]
  extend_active_record_relation
end
sort_option(key, string_or_proc = nil, opts = {}) click to toggle source

Macro for adding sort options

# File lib/filterer/base.rb, line 23
def sort_option(key, string_or_proc = nil, opts = {})
  if string_or_proc.is_a?(Hash)
    opts, string_or_proc = string_or_proc.clone, nil
  end

  if !string_or_proc
    if key.is_a?(String)
      string_or_proc = key
    else
      raise 'Please provide a query string or a proc.'
    end
  end

  if key.is_a?(Regexp) && opts[:default]
    raise "Default sort option can't have a Regexp key."
  end

  if string_or_proc.is_a?(Proc) && opts[:tiebreaker]
    raise "Tiebreaker can't be a proc."
  end

  self.sort_options += [{
    key: key,
    string_or_proc: string_or_proc,
    opts: opts
  }]
end

Public Instance Methods

defaults() click to toggle source
# File lib/filterer/base.rb, line 85
def defaults
  {}
end
direction() click to toggle source
# File lib/filterer/base.rb, line 93
def direction
  params[:direction].try(:downcase) == 'desc' ? 'desc' : 'asc'
end
starting_query() click to toggle source
# File lib/filterer/base.rb, line 89
def starting_query
  raise 'You must override this method!'
end

Private Instance Methods

add_params_to_query() click to toggle source
# File lib/filterer/base.rb, line 136
def add_params_to_query
  present_params.each do |k, v|
    method_name = "param_#{k}"

    if respond_to?(method_name)
      self.results = send(method_name, v) || results
    end
  end
end
apply_default_filters() click to toggle source
# File lib/filterer/base.rb, line 132
def apply_default_filters
  results
end
current_page() click to toggle source
# File lib/filterer/base.rb, line 170
def current_page
  [params[:page].to_i, 1].max
end
default_sort_option() click to toggle source
# File lib/filterer/base.rb, line 215
def default_sort_option
  self.class.sort_options.detect do |sort_option|
    sort_option[:opts][:default]
  end || filterer_default_sort_option
end
extend_active_record_relation() click to toggle source
# File lib/filterer/base.rb, line 235
def extend_active_record_relation
  results.instance_variable_set(:@filterer, self)

  results.extending! do
    def filterer
      @filterer
    end
  end
end
filterer() click to toggle source
# File lib/filterer/base.rb, line 239
def filterer
  @filterer
end
filterer_default_sort_option() click to toggle source
# File lib/filterer/base.rb, line 221
def filterer_default_sort_option
  {
    key: 'default',
    string_or_proc: "#{results.model.table_name}.id",
    opts: {}
  }
end
find_sort_option_from_param(x) click to toggle source

@param x [String] @return [Hash] sort_option

# File lib/filterer/base.rb, line 180
def find_sort_option_from_param(x)
  self.class.sort_options.detect do |sort_option|
    if sort_option[:key].is_a?(Regexp)
      x.match(sort_option[:key])
    else # String
      x == sort_option[:key]
    end
  end
end
order_by_sort_option(opt) click to toggle source
# File lib/filterer/base.rb, line 200
def order_by_sort_option(opt)
  results.order %{
    #{opt[:string_or_proc]}
    #{direction}
    #{opt[:opts][:nulls_last] ? 'NULLS LAST' : ''}
    #{tiebreaker_sort_string ? ', ' + tiebreaker_sort_string : ''}
  }.squish
end
order_by_sort_proc() click to toggle source
# File lib/filterer/base.rb, line 190
def order_by_sort_proc
  if (sort_string = sort_proc_to_string(sort_option))
    order_by_sort_option(sort_option.merge(
      string_or_proc: sort_string
    ))
  else
    order_by_sort_option(filterer_default_sort_option)
  end
end
ordered_results() click to toggle source
# File lib/filterer/base.rb, line 152
def ordered_results
  if sort_option && sort_option[:string_or_proc].is_a?(String)
    order_by_sort_option(sort_option)
  elsif sort_option && sort_option[:string_or_proc].is_a?(Proc)
    order_by_sort_proc
  else
    order_by_sort_option(default_sort_option)
  end
end
paginate_results() click to toggle source
# File lib/filterer/base.rb, line 110
def paginate_results
  if per_page && paginator
    send("paginate_results_with_#{paginator}")
  end
end
paginate_results_with_kaminari() click to toggle source
# File lib/filterer/base.rb, line 124
def paginate_results_with_kaminari
  self.results = results.page(current_page).per(per_page)
end
paginate_results_with_will_paginate() click to toggle source
# File lib/filterer/base.rb, line 128
def paginate_results_with_will_paginate
  self.results = results.paginate(page: current_page, per_page: per_page)
end
paginator() click to toggle source
# File lib/filterer/base.rb, line 116
def paginator
  if defined?(Kaminari)
    :kaminari
  elsif defined?(WillPaginate)
    :will_paginate
  end
end
parse_strong_parameters(params) click to toggle source
# File lib/filterer/base.rb, line 245
def parse_strong_parameters(params)
  params.try(:to_unsafe_h) || params
end
per_page() click to toggle source
# File lib/filterer/base.rb, line 162
def per_page
  if self.class.allow_per_page_override && params[:per_page].present?
    [params[:per_page].to_i, per_page_max].min
  else
    self.class.per_page
  end
end
present_params() click to toggle source
# File lib/filterer/base.rb, line 146
def present_params
  params.select do |_k, v|
    v.present?
  end
end
sort_option() click to toggle source
# File lib/filterer/base.rb, line 174
def sort_option
  @sort_option ||= find_sort_option_from_param(sort)
end
sort_proc_to_string(opt) click to toggle source
# File lib/filterer/base.rb, line 209
def sort_proc_to_string(opt)
  sort_key = opt[:key]
  matches = sort_key.is_a?(Regexp) && params[:sort].match(sort_key)
  instance_exec matches, &opt[:string_or_proc]
end
tiebreaker_sort_string() click to toggle source
# File lib/filterer/base.rb, line 229
def tiebreaker_sort_string
  self.class.sort_options.detect do |sort_option|
    sort_option[:opts][:tiebreaker]
  end.try(:[], :string_or_proc)
end