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) %ul - 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 } end
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}") : {} } end def available_filters self.methods.select { |m| m =~ /^filter_/ }.map { |m| m[7..-1].to_sym } end end
Use it in a specific model, by extending with the module you just made:
class Person < ActiveRecord::Base extend ChainableFilters end
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! ;)