Created
March 23, 2010 15:11
-
-
Save house9/341278 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# see http://gist.github.com/341290 (sort_index_controller_usage.rb) | |
# see http://gist.github.com/341295 (sort_index_view_usage.html.erb) | |
# The classes in this module help to enable sorting on index pages | |
# building sql order clauses and rendering html table header links | |
module SortIndex | |
SORT_KEY_ASC = 'asc' | |
SORT_KEY_DESC = 'desc' | |
SORT_DIRECTION_MAP = { | |
SORT_KEY_DESC => 'DESC', | |
SORT_KEY_ASC => 'ASC' | |
} | |
# The +SortIndex::Config+ class specifies all possible sort columns | |
# for a given controller action including the default column and the default order | |
class Config | |
attr_accessor :columns | |
attr_accessor :default_direction | |
def default | |
return @default | |
end | |
# The +initialize+ method; | |
# both the default and columns parameters contain key value pairs | |
# where the key is passed in the query string to the action and the | |
# value contains the sql order by value | |
# === Parameters | |
# * _default_ = Hash; must contain only one pair; automatically gets added to the columns member | |
# * _columns_ = Hash; one pair per sortable column | |
# * _default_direction_ = String; optional, if not specified order will be DESC | |
def initialize(default, columns, default_direction = nil) | |
@columns = columns | |
@default_direction = default_direction || SORT_KEY_DESC | |
raise "default only supports 1 pair" if default.length != 1 | |
default.each_pair { |key, value| | |
@default = value | |
@columns[key] = value | |
} | |
end | |
end | |
# The +SortIndex::Sortable+ class enable sorting on index pages | |
# avoids sql injection by only using values from the SortIndex::Config#columns | |
# Hash and not the values passed in the query string | |
class Sortable | |
# The +initialize+ method; | |
# === Parameters | |
# * _params_ = the controllers params Hash | |
# * _config_ = SortIndex::Config | |
# * _index_url_ = String; optional, if not specified will be the name of the controller | |
# ** Examples | |
# *** not specified /employees (the index action) | |
# *** specified /employees/special_action | |
def initialize(params, config, index_url = nil) | |
@config = config | |
@params = params | |
@index_url = index_url || params[:controller] | |
# sets up for building the sql order by | |
@sort_direction = SORT_DIRECTION_MAP[@params[:sort_direction]] || @config.default_direction | |
@sort_by = @config.columns[@params[:sort_by]] || @config.default | |
end | |
# The +order+ method returns the sql order criteria | |
# use with your find calls or via paginate from will_paginate plugin | |
def order | |
specified_sort_by || "#{@sort_by} #{@sort_direction}" | |
end | |
# The +header_link+ method returns a string of html containing the table header and a tags | |
# Example: <th><a href="/employess?sort_by=first_name&sort_direction=desc">First Name</a></th> | |
# If the column is the currently sorted column then a css class of current-sort-asc or current-sort-describe | |
# is applied; this allows you to use css to add visual indicators such as up and down arrows | |
# this method is called from the view; once per column | |
# === Parameters | |
# * _sort_key_ = String; must be one of the key values from SortIndex::Config | |
# * _display_ = The display text | |
# * _sortable_ = Boolean; default is true; | |
# ** passing false will not render an anchor tag; instead the display will be wrapped in a span | |
def header_link(sort_key, display, sortable = true) | |
if @config.columns[sort_key].nil? and sortable then | |
raise "Sort key of '#{sort_key}' not found. Check your controllers SortIndex::Config variable" | |
end | |
class_attr = "" | |
if @config.columns[sort_key] == @sort_by then | |
class_attr = " class='current-sort-#{@sort_direction.downcase}'" | |
end | |
a_href = "<a href=\"#{@index_url}?sort_by=#{sort_key}&sort_direction=#{next_direction}\" title=\"Sort by #{display}\">#{display}</a>" | |
if sortable == false then | |
a_href = "<span>#{display}</span>" | |
end | |
return "<th#{class_attr}>#{a_href}</th>" | |
end | |
# The +next_direction+ method is called by header_link and specifies which way the rendered | |
# links should sort. Returns the opposite of the current sort | |
def next_direction | |
sort_direction = SORT_KEY_ASC | |
if (@params[:sort_direction].nil?) then | |
sort_direction = (@sort_direction == SORT_KEY_ASC) ? SORT_KEY_DESC : SORT_KEY_ASC | |
elsif (@params[:sort_direction] == SORT_KEY_ASC) then | |
sort_direction = SORT_KEY_DESC | |
end | |
return sort_direction | |
end | |
# The +specified_sort_by+ method is called by order returns the sql order by criteria | |
# This can be more than one sql column; when it is multiple columns we apply the same direction to all | |
# For Example if you had one header column for Employee#full_name which mapped to two | |
# database columns first_name and last_name of the employees table the result would look like | |
# first_name DESC, last_name DESC or last_name DESC, first_name DESC depending on your configuration | |
def specified_sort_by | |
sort = @config.columns[@params[:sort_by]] | |
return nil if sort.nil? | |
return sort.split(',').map {|order_criteria| "#{order_criteria} #{@sort_direction}"}.join(',') | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment