Skip to content

Customizing Filters

berk edited this page Apr 19, 2012 · 14 revisions

Setup

In this document we will be using 3 models: User, Event and EventUser so we can demonstrate some amazing filtering capabilities of the gem. Here are the table definitions of the models.

Users Table

create_table :users do |t|
   t.string    :first_name
   t.string    :last_name
   t.date      :birthday
   t.string    :sex
   t.timestamps
 end

Events Table

create_table :events do |t|
  t.integer   :creator_id
  t.string    :type
  t.string    :name
  t.string    :headline
  t.datetime  :start_time
  t.datetime  :end_time

  t.timestamps
end
add_index :events, [:creator_id]

Event Users Table

create_table :event_users do |t|
  t.integer :event_id
  t.integer :user_id
  t.timestamps
end
add_index :event_users, [:event_id]
add_index :event_users, [:user_id]
add_index :event_users, [:event_id, :user_id]

Here are the actual model objects with their associations:

User Model

class User < ActiveRecord::Base
  has_many :events
  has_many :events_users
end

Event Model

class Event < ActiveRecord::Base
  belongs_to :user, :class_name => 'User', :foreign_key => :creator_id
  has_many :event_users
end

EventUser Model

class EventUser < ActiveRecord::Base
  belongs_to :event
  belongs_to :user
end

We will also use a samples_controller with an index action. The controller code looks like this:

class SamplesController < ApplicationController
  def index
    # All examples assume you are placing the code in here
  end
end

The index.html.erb will simply look like this:

<%= will_filter_tag(@users)%>

In some cases we will use @users in other cases @events or @event_users

Basic Filters

Creating a basic filter is just a matter of adding the following lines of code to your controller:

class OrdersController < ApplicationController

  def index
    @users = User.filter(:params => params)
  end

end

And adding a filter display tags to your page: (index.html.erb)

<%= will_filter_tag(@users) %>

If you would like to display the will_filter table, you can add the following tag right below the filter tag: (index.html.erb)

<%= will_filter_table_tag(@orders) %>

Note: Since we are not going to be looking at the table tag here, assume it is always present on the page.

This will create the following filter on the page:

Filter with conditions will look like:

Filters Explained

What is a filter? Well, filter is simply a collection of conditions and some additional attributes, like pagination, sorting, etc…

A filter condition is comprised of 3 elements: model attribute key, operator and container. Operators and containers options are dynamically discovered based on the column data type.

If you look at the config/will_filter/config.yml you will see that operators and containers can be easily added or modified based on the application needs.

Here is what the config looks like:

containers:             # container implementation mapping
  nil:                  WillFilter::Containers::Nil
  numeric:              WillFilter::Containers::Numeric
  numeric_range:        WillFilter::Containers::NumericRange
  numeric_delimited:    WillFilter::Containers::NumericDelimited
  double:               WillFilter::Containers::Double
  double_range:         WillFilter::Containers::DoubleRange
  double_delimited:     WillFilter::Containers::DoubleDelimited
  date_time_range:      WillFilter::Containers::DateTimeRange
  single_date:          WillFilter::Containers::SingleDate
  date:                 WillFilter::Containers::Date
  date_time:            WillFilter::Containers::DateTime
  date_range:           WillFilter::Containers::DateRange
  text:                 WillFilter::Containers::Text
  text_delimited:       WillFilter::Containers::TextDelimited
  boolean:              WillFilter::Containers::Boolean
  list:                 WillFilter::Containers::List
  filter_list:          WillFilter::Containers::FilterList

data_types:             # mapping between data types and containers   
  bigint:               [nil, numeric, numeric_range, numeric_delimited]
  numeric:              [nil, numeric, numeric_range, numeric_delimited]
  smallint:             [nil, numeric, numeric_range, numeric_delimited]
  integer:              [nil, numeric, numeric_range, numeric_delimited]
  int:                  [nil, numeric, numeric_range, numeric_delimited]
  float:                [nil, double, double_range, double_delimited]
  double:               [nil, double, double_range, double_delimited]
  timestamp:            [nil, date_time, date_time_range, single_date]
  datetime:             [nil, date_time, date_time_range, single_date]
  date:                 [nil, date, date_range]
  char:                 [nil, text, text_delimited]
  character:            [nil, text, text_delimited]
  varchar:              [nil, text, text_delimited]
  text:                 [nil, text, text_delimited]
  text[]:               [nil, text, text_delimited]
  bytea:                [nil, text, text_delimited]
  boolean:              [nil, boolean]
  tinyint:              [nil, boolean]

operators:              # operators precedence
  is:                   100
  is_not:               200
  is_on:                300
  is_in:                400
  is_provided:          500
  is_not_provided:      600 
  is_after:             700
  is_before:            800
  is_in_the_range:      900
  contains:             1000
  does_not_contain:     1100
  starts_with:          1200
  ends_with:            1300
  is_greater_than:      1400
  is_less_than:         1500
  is_filtered_by:       1600

The data_types section maps each data type to an array of available containers, while each container provides information on which operators it supports.

The entire framework is very customizable so you can add custom containers, operators and data types.

Clone this wiki locally