# iain.nl

Filtering with named scopes (encore)

Written on

In my previous post, I talked about making filters using named scopes. To summorize:

I like the method of using a named_scope and delegating to specified filters. This way, you can structure your filters properly and get clean URLs. Also, you can chain other named scopes to the filter.

If you find yourself making an administrative web application, with many tables and filters, here's an example to make it a little more DRY.

Making a partial

First, make the filters a partial, in something like app/views/shared/_filters.html.haml.

%h3= t(model_name, :scope => :filter_titles)
  - model_class.available_filters.each do |filter|
    %li= link_to t(filter, :scope => [:filter_names, model_name]), url_for(params.merge(:filter => filter))

I've changed the translate-calls a bit, so they work with different models.

A helper method

Then, create a helper method:

def show_filters_for(model_name)
  render :partial => "shared/filters",
         :locals => { :model_name => model_name, :model_class => model_name.to_s.camilze.constantize }

Now you can render the filters like this:

= show_filters_for :person

And a module

On the model side, you can make a module, probably in lib/chainable_filters.rb.

module ChainableFilters

  def self.extended(model)
    model.named_scope :filter, lambda { |f|
      model.available_filters.include?(f) ? model.send("filter_#{f}") : {}

  def available_filters
    self.methods.select { |m| m =~ /^filter_/ }.map { |m| m[7..-1].to_sym }


Use it in a specific model, by extending with the module you just made:

class Person < ActiveRecord::Base
  extend ChainableFilters

Or just every ActiveRecord class, by creating an initializer file (i.e. config/initializers/chainable_filters.rb):

ActiveRecord::Base.extend ChainableFilters

Now, that is some nice meta-programming, if you ask me! ;)