class Filterameter::ControllerFilters

Controller Filters

Class ControllerFilters stores the configuration declared via class-level method calls such as the list of filters and the optionally declared model class. Each controller will have one instance of the controller declarations stored as a class variable.

Attributes

query_variable_name[W]

Public Class Methods

new(controller_name, controller_path) click to toggle source
# File lib/filterameter/controller_filters.rb, line 24
def initialize(controller_name, controller_path)
  @controller_name = controller_name
  @controller_path = controller_path
  @declarations = {}
  @ranges = {}
  @filters = Hash.new { |hash, key| hash[key] = filter_factory.build(@declarations[key]) }
end

Public Instance Methods

add_filter(parameter_name, options) click to toggle source
# File lib/filterameter/controller_filters.rb, line 36
def add_filter(parameter_name, options)
  @declarations[parameter_name.to_s] =
    Filterameter::FilterDeclaration.new(parameter_name, options).tap do |fd|
      add_declarations_for_range(fd, options, parameter_name) if fd.range_enabled?
    end
end
build_query(filter_params, starting_query) click to toggle source
# File lib/filterameter/controller_filters.rb, line 47
def build_query(filter_params, starting_query)
  valid_filters(filter_params)
    .tap { |parameters| convert_min_and_max_to_range(parameters) }
    .reduce(starting_query || model_class.all) do |query, (name, value)|
    @filters[name].apply(query, value)
  end
end
model_class=(model_class) click to toggle source
# File lib/filterameter/controller_filters.rb, line 32
def model_class=(model_class)
  @model_class = model_class.is_a?(String) ? model_class.constantize : model_class
end
query_variable_name() click to toggle source
# File lib/filterameter/controller_filters.rb, line 43
def query_variable_name
  @query_variable_name ||= model_class.model_name.plural
end

Private Instance Methods

add_declarations_for_range(attribute_declaration, options, parameter_name) click to toggle source

if range is enabled, then in addition to the attribute filter this also adds min and/or max filters

# File lib/filterameter/controller_filters.rb, line 127
def add_declarations_for_range(attribute_declaration, options, parameter_name)
  add_range_minimum(parameter_name, options) if attribute_declaration.range? || attribute_declaration.minimum?
  add_range_maximum(parameter_name, options) if attribute_declaration.range? || attribute_declaration.maximum?
  capture_range_declaration(parameter_name) if attribute_declaration.range?
end
add_range_maximum(parameter_name, options) click to toggle source
# File lib/filterameter/controller_filters.rb, line 138
def add_range_maximum(parameter_name, options)
  @declarations["#{parameter_name}_max"] = Filterameter::FilterDeclaration.new(parameter_name,
                                                                               options.merge(range: :max_only))
end
add_range_minimum(parameter_name, options) click to toggle source
# File lib/filterameter/controller_filters.rb, line 133
def add_range_minimum(parameter_name, options)
  @declarations["#{parameter_name}_min"] = Filterameter::FilterDeclaration.new(parameter_name,
                                                                               options.merge(range: :min_only))
end
capture_range_declaration(name) click to toggle source

memoizing these makes it easier to spot and replace ranges in query parameters; see convert_min_and_max_to_range

# File lib/filterameter/controller_filters.rb, line 144
def capture_range_declaration(name)
  @ranges[name] = { min: "#{name}_min", max: "#{name}_max" }
end
convert_min_and_max_to_range(parameters) click to toggle source

if both min and max are present in the query parameters, replace with range

# File lib/filterameter/controller_filters.rb, line 76
def convert_min_and_max_to_range(parameters)
  @ranges.each do |attribute_name, min_max_names|
    next unless min_max_names.values.all? { |min_max_name| parameters[min_max_name].present? }

    parameters[attribute_name] = Range.new(parameters.delete(min_max_names[:min]),
                                           parameters.delete(min_max_names[:max]))
  end
end
declared_parameter_names() click to toggle source
# File lib/filterameter/controller_filters.rb, line 118
def declared_parameter_names
  @declared_parameter_names ||= @declarations.keys
end
filter_factory() click to toggle source

lazy so that model_class can be optionally set

# File lib/filterameter/controller_filters.rb, line 65
def filter_factory
  @filter_factory ||= Filterameter::FilterFactory.new(model_class)
end
handle_undeclared_parameters(filter_params) click to toggle source
# File lib/filterameter/controller_filters.rb, line 91
def handle_undeclared_parameters(filter_params)
  action = Filterameter.configuration.action_on_undeclared_parameters
  return unless action

  undeclared_parameter_names = filter_params.keys - declared_parameter_names
  case action
  when :log
    ActiveSupport::Notifications.instrument('undeclared_parameters.filterameter', keys: undeclared_parameter_names)
  when :raise
    raise Filterameter::Exceptions::UndeclaredParameterError, undeclared_parameter_names
  end
end
model_class() click to toggle source
# File lib/filterameter/controller_filters.rb, line 57
def model_class
  @model_class ||= @controller_name.classify.safe_constantize ||
                   @controller_path.classify.safe_constantize ||
                   raise(Filterameter::Exceptions::CannotDetermineModelError.new(@controller_name,
                                                                                 @controller_path))
end
remove_invalid_values(filter_params) click to toggle source
# File lib/filterameter/controller_filters.rb, line 104
def remove_invalid_values(filter_params)
  validator = validator_class.new(filter_params)
  return filter_params if validator.valid?

  case Filterameter.configuration.action_on_validation_failure
  when :log
    ActiveSupport::Notifications.instrument('validation_failure.filterameter', errors: validator.errors)
  when :raise
    raise Filterameter::Exceptions::ValidationError, validator.errors
  end

  filter_params.except(*validator.errors.keys.map(&:to_s))
end
remove_undeclared_filters(filter_params) click to toggle source
# File lib/filterameter/controller_filters.rb, line 85
def remove_undeclared_filters(filter_params)
  filter_params.slice(*declared_parameter_names).tap do |declared_parameters|
    handle_undeclared_parameters(filter_params) if declared_parameters.size != filter_params.size
  end
end
valid_filters(filter_params) click to toggle source
# File lib/filterameter/controller_filters.rb, line 69
def valid_filters(filter_params)
  remove_invalid_values(
    remove_undeclared_filters(filter_params)
  )
end
validator_class() click to toggle source
# File lib/filterameter/controller_filters.rb, line 122
def validator_class
  @validator_class ||= Filterameter::ParametersBase.build_sub_class(@declarations.values)
end