Skip to content

Instantly share code, notes, and snippets.

@knoopx
Last active November 18, 2015 16:14
Show Gist options
  • Save knoopx/3954515f862d3ca2d155 to your computer and use it in GitHub Desktop.
Save knoopx/3954515f862d3ca2d155 to your computer and use it in GitHub Desktop.
module FiltrableModel
def filter_class=(klass)
@filter_class = klass
end
def filter(params = {})
@filter_class or raise "No filter model specified"
@filter_class.new(self).apply(params)
end
end
class Order
extend FiltrableModel
filter_class OrderFilter
end
class Filter
PREDICATES = {
eq: ->(scope, value) { scope.where(scope.arel_table[@name].eq(value)) },
cont: ->(scope, value) { scope.where(scope.arel_table[@name].matches("%#{value}%")) },
}
class << self
def mapping
@mapping ||= {}
end
def param(name, &apply)
mapping[name] = apply
end
def column(name, opts = {})
predicate = PREDICATES[opts.fetch(:predicate, :eq)] or raise "Unknown predicate: #{name}"
param("#{name}_#{predicate}", &predicate)
end
end
def initialize(scope)
@scope = scope
end
def apply(params = {})
self.class.mapping.inject(scope) do |scope, (name, apply)|
apply.call(scope, params[name]) if params.key?(name)
end
end
end
class OrderFilter < Filter
param(:custom) { |scope, value| scope.where(yay: value) }
column(:ref)
end
class OrderController < ApplicationController
def index
@orders = filter_scope.order(created_at: :desc)
end
def scope
Order.where(deleted_at: nil)
end
def filter_scope
scope.filter(params[:filter])
end
end
@sendorf
Copy link

sendorf commented Nov 18, 2015

You may add another type of predicate for segmented strings with multiple terms (to search something like "La casa de la pradera" with this query "cas dera"), you could add something like
seg: ->(scope, value) { scope.where(scope.arel_table[@name].matches_all(value.split(" ").map{|x| "%#{x}%"})) },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment