EasyFilters

This gem provides a simple API for defining dynamic persistent(in session) filters based on active record models.

Installation

Add this line to your application's Gemfile:


    gem 'easy_filters'

And then execute:


    $ bundle

Usage

Create a articles_filter.rb file in app/models/easy_filters folder EasyFilters expects you to define the following methods:

module EasyFilters

  class ArticlesFilter < ModelFilter

    # Default values for this filter.
    def self.defaults
      { body: nil, date_from: nil, date_to: nil }
    end

    # Model class to be filtered.
    def model
      Article
    end
  end
end

  • defaults: defines the fields that will be used for filtering and its defaults values
  • model: returns the target class to be filtered

Customizing filtering strategy

For defining the parts of the query that will filter each each field, define a method named filter_by_#{field_name}. The field must be present in the defaults array.

Each filter_by_* method receives 2 params:

  • scope: The actual query.
  • value: The value for the current field

For example:


module EasyFilters

  class ArticlesFilter < ModelFilter

    #(...) previously defined methods

    # Custom filter method for :body field.
    def filter_by_body(scope, value)
      matcher = "%#{value}%"
      scope.where('body like ? OR body like ?', matcher, matcher)
    end

    # The following 2 filter_by builds an from/to/between date filter:

    # Custom filter method for :date_from field.
    def filter_by_date_from(scope, value)
      scope.joins(:editions).where('editions.date >= ?', Date.parse(value))
    end

    # Custom filter method for :date_to field.
    def filter_by_date_to(scope, value)
      scope.joins(:editions).where('editions.date <= ?', Date.parse(value))
    end
  end
end

Usage in controllers

You can instance a filter in your controller, and define some usefull methods

For example:


  #(...) previously defined controller

  before_action :filter,       only: [:filter_page]
  before_action :clear_filter, only: [:filter_page]

  def filter_page
    @objects = @filter.all
  end

  private

  def create_filter(filter_class, opts = {})
      options = { store: session, persist: true }.merge opts
      filter_class.new options
  end

  def filter_params
    if params.has_key?(:filter)
      params.require(:filter).permit(:body, :date_from, :date_to).to_options
    end
  end

  # Create the @filter object with the currently-set values for the filters
  def filter
    @filter = create_filter EasyFilters::ArticlesFilter, values: filter_params
  end

  # Clear the currently-set filters, restoring them to the defaults
  def clear_filter
    if params[:commit] == t('common.filters.clear')
      @filter.clear!
      redirect_to request.path
    end
  end

Usage in views

Define a input with the filter


<% form_tag '', :method => :get do %>
    <%= label :filter, :body %>
    <%= text_field :filter, :body %>
    <%= submit_tag t('common.filters.search') %>
    <%= submit_tag t('common.filters.clear') %>
<% end %>