DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Smart Filters

10.24.2008
| 3218 views |
  • submit to reddit
        I have an application that houses thousands of companies.  How do we filter through such a large list?  We could just slap will_paginate in there to filter through 100's of pages, but that doesn't seem very agile.  Let's set this up so we can filter several different object variables.

Scenario: We want to categorize companies by their type (ie Client, Vendor, Contractor...).  We also want to be able to browse each category by what alpha it starts with (A, B, C, etc.) all while displaying what parameters are current by highlighting the selected params.  This is fairly simple and you may want to refactor as needed.

A screenshot of the output can be found here: http://www.flickr.com/photos/patrickonflickr/2970095598/in/set-72157608341135199/
A video demonstration of the output can be found here: http://vimeo.com/2058860


app/controllers/companies_controller.rb

def index
    # Set instance variables for our view...if selected then highlight
    @category = params[:category].blank? ? "%" : params[:category] 
    @alpha = params[:alpha].blank? ? "%" : params[:alpha]
    
    # If we're filtering category include it in the find
    includes = params[:category] ? [:company_category] : nil
    
    # build an array of conditions
    @conditions = []
    @con1 = params[:category] ? (@conditions << "company_categories.cat_name = '#{params[:category]}'") : nil
    @con2 = params[:alpha] ? (@conditions << "companies.name LIKE '#{params[:alpha]}%'") : nil
    
    # count the number of records returned with includes and conditions set
    @company_count = Company.count(:include => includes, :conditions => @conditions.join(" and "))
    
    # Finally, our find
    @companies = Company.paginate :page => params[:page], :per_page => 10, :order => 'name', :include => includes, :conditions => @conditions.join(" and ")
    
    respond_to do |format|
      format.html
      format.xml  { render :xml => @companies }
    end
end

app/views/companies/index.html

<div id="filter">
	<div class="pagination" style="margin-top: 0">
		<%= pluralize(@company_count, 'Company') %> <%= will_paginate(@companies) %>
	</div>
	<table width="100%" id="filter">
		<tr>
			<th>Categories</th>
			<td>
				<ul class="filter">
				<li><%= @category.include?("%") ? "<span>All</span>" : (link_to "All", companies_path(params.merge(:category => nil, :page => nil))) %></li>
				<li><b>|</b></li>
				<% for type in CompanyCategory.all(:order => 'cat_name') %>
					<li><%= @category.include?(type.cat_name) ? "<span>#{type.cat_name}</span>" : (link_to type.cat_name, companies_path(params.merge(:category => type.cat_name, :page => nil))) %></li>
				<% end %>
				</ul>
			</td>
		</tr>
		<tr>
			<th>By letter</th>
			<td>
				<ul class="filter">
					<li><%= @alpha.include?("%") ? "<span>All</span>" : (link_to "All", companies_path(params.merge(:alpha => "%", :page => nil))) %></li>
					<li><b>|</b></li>
					<% ("A".."Z").each do |alpha| %>
						<li><%= @alpha.include?(alpha) ? "<span>#{alpha}</span>" : (link_to alpha, companies_path(params.merge(:alpha => alpha, :page => nil))) %></li>
					<% end %>
				</u>
			</td>
		</tr>
		<tr>
			<th>Has Invoices</th>
			<td>
				<ul class="filter">
					<li>Paid</li>
					<li>Pending</li>
					<li>Awaiting to be sent</li>
					<li>A/R</li>
				</u>
			</td>
		</tr>
	</table>
</div>

public/stylesheets/style.css

div.company {
	padding: 5px;
	border-bottom: 1px dotted #222;
}
div.company h1 {
	font-size: 14px;
	padding: 5px 0;
}
div.even {
	background: #f5f5f5;
}
table#filter {
	margin: 0 0 15px 0;
}
table#filter th {
	font-size: 10px;
	padding: 0 10px;
	margin: 0;
	background: #ccc;
}
table#filter td {
	background: #e7e7e7;
	font-size: 10px;
}

ul.filter {
	margin: 5px 0 0 0;
	padding: 0;
}
ul.filter li {
	margin: 0 5px;
	float: left;
}
ul.filter li a {
	text-decoration: none;
}
ul.filter li span {
	background: #ffffcc;
	font-weight: bold;
	text-decoration: underline;
}