Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

An attempt to generalize filtering of AR objects

branch: master
README.textile

Simplificator Filter

An Extension to ActiveRecord in order to manage filtering and ordering of collections.

Install

  gem install simplificator-filter

Usage

You can define filters and orders in your models and then using this definitions to retrieve the data.
See the examples below.

Filter

Definition

Assume you have a product model with name:string, price:integer and available_as_of:date as attributes. Then you could define the following filter definition in your product class.


filter_definition do |filter|
filter.fuzzy_name :strategy => :like, :attribute => ‘name’
filter.price_range :strategy => :between, :attribute => ‘price’
filter.available_as_of :strategy => :equal
end

You can use different strategies according to the attributes type. For string you can define :like, :begins_with, :ends_with or :equal.
The strategy option is not mandatory, if not set then the default strategy for that attributes type is used. For a string type this would be the :like strategy.
(See filter strategies for more information)

If you just want a filter with the same name as the attribute and its default strategy, you can use:

  default_filter_for_attribute :name
  default_filters_for_attributes :name, :price

or just define for all your attributes a default filter:

  default_filters_for_all_attributes

filter_by

Keeping the first definition as example, you can now use the filter_by class method:

  Product.filter_by(:fuzzy_name => 'carpet')
  Product.filter_by(:fuzzy_name => 'carpet', :price_range => '15 - 45')
  Product.filter_by(:fuzzy_name => 'carpet', :price_range => '15 - 45', :available_as_of => 1.day.ago.to_date)

filter_by returns a scope, therefore you can use it with your other scopes or with will_paginate.

  Product.cheap.filter_by(:fuzzy_name => 'carpet').red
  Product.cheap.filter_by(:fuzzy_name => 'carpet').red.paginate(:page => 2)

Associations

You can even filter associated attributes. Let’s add an order model with following associations and filter definition.

  belongs_to :product
  belongs_to :customer

  filter_definition do |filter|
    filter.customer_name :strategy => :like, :attribute => 'customer.name'
    filter.product_name :strategy => :like, :attribute => 'product.name'
    filter.purchased_at :strategy => :equal
  end

The filter_by works still the same way, all necessary tables are included automatically.

  Product.filter_by(:customer_name => 'foo', :product_name => 'magic carpet')

Filter Forms

  <% form_for @products.filter |f| %>
    <%= f.input_field f.fuzzy_name %>
    <%= f.input_field f.price_range %>
    <%= f.input_field f.purchased_at %>
    <%= f.sumbit_tag 'Filter' %>
  <% end %>

In your controller you can just use:


@products = Product.filter_by params[:filter]

View Helpers

Filter Strategies

Type strategies default
string :like, :begins_with, :ends_with, :like
text :like, :begins_with, :ends_with, :like
integer :equal, :between :equal
float :equal, :between :equal
time :equal, :between :equal
date :equal, :between :equal
datetime :equal, :between :equal
binary :equal, :equal
boolean :equal, :equal

Patterns

If you define more than one strategy for an attribute or leave it completly.

  filter_definition do |filter|
    filter.name :strategy => [:begins_with, :ends_with]
    filter.price
  end

In this cases filter_by tries to match a pattern against the passed value to detect the right strategy.
If name matches “* carpet” a :ends_with strategy would be applied, if it would match "magic* " a :begins_with would be used.
If no pattern matches, then default strategy is used.
The only difference between the first and the second filter definition is: If a pattern could be found but it is not included in the array passed, an ArgumentError will be raised.

Patterns

pattern strategy
/^\(.?)\*$/ :like
/^\(.?)$/, :ends_with
/^(.?)\$/, :begins_with
/^(-?\d+)\s?-\s?(-?\d+)$/ :between

Order


Something went wrong with that request. Please try again.