Adventures with Ruby

Filtering with named scopes (encore)

View Comments

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.

[sourcecode language='ruby']
%h3= t(model_name, :scope => :filter_titles)
%ul
– model_class.available_filters.each do |filter|
%li= link_to t(filter, :scope => [:filter_names, model_name]), url_for(params.merge(:filter => filter))
[/sourcecode]

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

A helper method

Then, create a helper method:

[sourcecode language='ruby']
def show_filters_for(model_name)
render :partial => “shared/filters”, :locals => { :model_name => model_name, :model_class => model_name.to_s.camilze.constantize }
end
[/sourcecode]

Now you can render the filters like this:

[sourcecode language='ruby']
= show_filters_for :person
[/sourcecode]

And a module

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

[sourcecode language='ruby']
module ChainableFilters

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

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

end
[/sourcecode]

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

[sourcecode language='ruby']
class Person < ActiveRecord::Base
extend ChainableFilters
end
[/sourcecode]

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

[sourcecode language='ruby']ActiveRecord::Base.extend ChainableFilters[/sourcecode]

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

Written by Iain Hecker

June 17th, 2009 at 5:17 pm

Posted in Uncategorized

  • Phil Kursawe

    hmmm, still not sure how you would use that to chain filters together. Instead of link_to wouldn’t you need some kind of checkbox form where you can select the filters or even provide some input fields for filter criteria?
    I would like to filter something like this:
    adults with name like ‘Carl’
    and would have an input field for “name” and a checkbox for “adult”.

  • Phil Kursawe

    hmmm, still not sure how you would use that to chain filters together. Instead of link_to wouldn’t you need some kind of checkbox form where you can select the filters or even provide some input fields for filter criteria?
    I would like to filter something like this:
    adults with name like ‘Carl’
    and would have an input field for “name” and a checkbox for “adult”.

blog comments powered by Disqus
Fork me on GitHub