From e9f7340b655706ad603bd0b18abed5b617971206 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Tue, 8 Feb 2011 13:46:02 +0000 Subject: [PATCH 1/8] added ability to define sortable_methods on an object, letting you sort by columns plus named methods --- lib/helpers/view_helpers.rb | 2 +- lib/sortable_columns.rb | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/helpers/view_helpers.rb b/lib/helpers/view_helpers.rb index 4fa126b..a0cb619 100644 --- a/lib/helpers/view_helpers.rb +++ b/lib/helpers/view_helpers.rb @@ -4,7 +4,7 @@ module ViewHelpers def sort_params(sortable, column) raise ParameterError.new("Please provide a Class as your first param. Ex: sort_param(User, :created_at)") unless sortable.is_a?(Class) - raise ParameterError.new("#{sortable} has no column \"#{column}\".") unless sortable.column_names.include?(column.to_s) + raise ParameterError.new("#{sortable} has no column \"#{column}\".") unless sortable_attributes_and_methods(sortable).include?(column.to_s) init_session unless session[:sortable_columns] diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index 53e9e5f..338a84d 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -17,10 +17,15 @@ def sortable_order(sortable, options = {}) end end + def sortable_attributes_and_methods( sortable ) + columns = sortable.column_names + columns += sortable.sortable_methods if sortable.respond_to?( :sortable_methods ) + end + private def validate_params(sortable) - raise ParameterError.new("#{sortable} has no column \"#{params[:sort_by]}\".") unless sortable.column_names.include?(params[:sort_by]) + raise ParameterError.new("#{sortable} has no column \"#{params[:sort_by]}\".") unless sortable_attributes_and_methods(sortable).include?(params[:sort_by]) raise ParameterError.new("Order must be \"asc\" or \"desc\"") unless params[:order] == "asc" || params[:order] == "desc" end From 4c63a17b18c8c43a36a04543409e0d8679a326a7 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Tue, 8 Feb 2011 13:49:27 +0000 Subject: [PATCH 2/8] scoped method call --- lib/sortable_columns.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index 338a84d..e0a8e1a 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -25,7 +25,7 @@ def sortable_attributes_and_methods( sortable ) private def validate_params(sortable) - raise ParameterError.new("#{sortable} has no column \"#{params[:sort_by]}\".") unless sortable_attributes_and_methods(sortable).include?(params[:sort_by]) + raise ParameterError.new("#{sortable} has no column \"#{params[:sort_by]}\".") unless SortableColumns::sortable_attributes_and_methods(sortable).include?(params[:sort_by]) raise ParameterError.new("Order must be \"asc\" or \"desc\"") unless params[:order] == "asc" || params[:order] == "desc" end From 4e49be68fa02c7b3b3f006f79ae755066855b9d4 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Tue, 8 Feb 2011 14:58:40 +0000 Subject: [PATCH 3/8] can now add sortable_methods :method_1, :method_2 on an AR class, to allow sorting by methods (not just columns) --- init.rb | 4 +++- lib/helpers/active_record_base_methods.rb | 10 ++++++++++ lib/helpers/view_helpers.rb | 4 +--- lib/sortable_columns.rb | 16 ++++++++++------ 4 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 lib/helpers/active_record_base_methods.rb diff --git a/init.rb b/init.rb index 00e9bb8..b8976de 100644 --- a/init.rb +++ b/init.rb @@ -1,5 +1,7 @@ require 'sortable_columns' require 'helpers/view_helpers' +require 'helpers/active_record_base_methods' ActionController::Base.send(:include, SortableColumns) -ActionView::Base.send(:include, SortableColumns::ViewHelpers) \ No newline at end of file +ActionView::Base.send(:include, SortableColumns::ViewHelpers) +ActiveRecord::Base.send(:extend, SortableColumns::ActiveRecordBaseMethods) \ No newline at end of file diff --git a/lib/helpers/active_record_base_methods.rb b/lib/helpers/active_record_base_methods.rb new file mode 100644 index 0000000..8b48ac1 --- /dev/null +++ b/lib/helpers/active_record_base_methods.rb @@ -0,0 +1,10 @@ +module SortableColumns + + module ActiveRecordBaseMethods + attr_accessor :sortable_methods + + def sortable_instance_methods(methods) + @sortable_methods = methods.to_a + end + end +end \ No newline at end of file diff --git a/lib/helpers/view_helpers.rb b/lib/helpers/view_helpers.rb index a0cb619..f46dc7c 100644 --- a/lib/helpers/view_helpers.rb +++ b/lib/helpers/view_helpers.rb @@ -3,9 +3,7 @@ module SortableColumns module ViewHelpers def sort_params(sortable, column) - raise ParameterError.new("Please provide a Class as your first param. Ex: sort_param(User, :created_at)") unless sortable.is_a?(Class) - raise ParameterError.new("#{sortable} has no column \"#{column}\".") unless sortable_attributes_and_methods(sortable).include?(column.to_s) - + SortableColumns.validate_params(sortable, :sort_by=>column) init_session unless session[:sortable_columns] if session[:sortable_columns][sortable.to_s.downcase.to_sym] diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index e0a8e1a..44fb43d 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -4,7 +4,7 @@ class ParameterError < StandardError; end def sortable_order(sortable, options = {}) if params[:sort_by] && params[:order] - validate_params(sortable) + validate_params(sortable, params) store_sort(sortable) return "#{params.delete(:sort_by)} #{params.delete(:order)}" else @@ -20,14 +20,18 @@ def sortable_order(sortable, options = {}) def sortable_attributes_and_methods( sortable ) columns = sortable.column_names columns += sortable.sortable_methods if sortable.respond_to?( :sortable_methods ) + columns.map{ |c| c.to_s } end -private - - def validate_params(sortable) - raise ParameterError.new("#{sortable} has no column \"#{params[:sort_by]}\".") unless SortableColumns::sortable_attributes_and_methods(sortable).include?(params[:sort_by]) - raise ParameterError.new("Order must be \"asc\" or \"desc\"") unless params[:order] == "asc" || params[:order] == "desc" + def validate_params(sortable, params) + puts "params[:order] = #{params[:order].inspect}\n\nsortable_attributes_and_methods( sortable ) = #{sortable_attributes_and_methods( sortable ).inspect}\n\n" + raise ParameterError.new("#{sortable} has no column or sortable_method \"#{params[:sort_by]}\". \n\nIf you're trying to sort by an instance method that isn't a column name (e.g. a value from an associated table), you must define \n\n\tsortable_instance_methods :my_method_1, :my_method_2 \n\nin your model class. Don't forget to include it as a column in your query too!") unless SortableColumns.sortable_attributes_and_methods(sortable).include?(params[:sort_by].to_s) + raise ParameterError.new("Order must be \"asc\" or \"desc\" - you gave #{params[:order]}") unless params[:order].blank? || ["asc","desc"].include?(params[:order].to_s.downcase) end + + module_function :sortable_attributes_and_methods, :validate_params + +private def store_sort(sortable) session[:sortable_columns] ||= Hash.new From 07e81a8745f372a778447dd6ea910b551906bac3 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Thu, 10 Feb 2011 12:19:28 +0000 Subject: [PATCH 4/8] sort_params now preserves existing params on links --- lib/helpers/view_helpers.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/helpers/view_helpers.rb b/lib/helpers/view_helpers.rb index f46dc7c..79a9c7c 100644 --- a/lib/helpers/view_helpers.rb +++ b/lib/helpers/view_helpers.rb @@ -8,14 +8,14 @@ def sort_params(sortable, column) if session[:sortable_columns][sortable.to_s.downcase.to_sym] if session[:sortable_columns][sortable.to_s.downcase.to_sym][column.to_sym] == "asc" - return { :sort_by => column.to_s, :order => 'desc' } + return params.merge( { :sort_by => column.to_s, :order => 'desc' } ) else - return { :sort_by => column.to_s, :order => 'asc' } + return params.merge( { :sort_by => column.to_s, :order => 'asc' } ) end end # default - return { :sort_by => column.to_s, :order => 'desc' } + return params.merge( { :sort_by => column.to_s, :order => 'desc' } ) end private From d82938b0cee9538301add0bca2e94a24c71a51f5 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Thu, 10 Feb 2011 12:35:02 +0000 Subject: [PATCH 5/8] add before_filter to ApplicationController so that it automatically preserves params --- init.rb | 4 ++++ lib/sortable_columns.rb | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/init.rb b/init.rb index b8976de..c3b9b59 100644 --- a/init.rb +++ b/init.rb @@ -3,5 +3,9 @@ require 'helpers/active_record_base_methods' ActionController::Base.send(:include, SortableColumns) +# allow sort_params to preserve existing params +# (minus standard params like :controller, :action, etc ) +ApplicationController.send( :append_before_filter, :store_params) + ActionView::Base.send(:include, SortableColumns::ViewHelpers) ActiveRecord::Base.send(:extend, SortableColumns::ActiveRecordBaseMethods) \ No newline at end of file diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index 44fb43d..2e3d877 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -29,6 +29,11 @@ def validate_params(sortable, params) raise ParameterError.new("Order must be \"asc\" or \"desc\" - you gave #{params[:order]}") unless params[:order].blank? || ["asc","desc"].include?(params[:order].to_s.downcase) end + + def store_params + @params = params.clone - [ :controller, :action, :authenticity_token, :page, :format, :per_page ] + end + module_function :sortable_attributes_and_methods, :validate_params private From a308e767e49df6e2cadd3d61d21a9121e43a55bf Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Thu, 10 Feb 2011 12:53:07 +0000 Subject: [PATCH 6/8] fixed bug with nil sortable_methods --- lib/sortable_columns.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index 2e3d877..9a49fe6 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -19,7 +19,7 @@ def sortable_order(sortable, options = {}) def sortable_attributes_and_methods( sortable ) columns = sortable.column_names - columns += sortable.sortable_methods if sortable.respond_to?( :sortable_methods ) + columns += sortable.sortable_methods.to_a if sortable.respond_to?( :sortable_methods ) columns.map{ |c| c.to_s } end From 9d0266404e5c68099b03c89bdeeb6703752f50b9 Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Fri, 11 Feb 2011 12:52:09 +0000 Subject: [PATCH 7/8] took out debug code --- lib/sortable_columns.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index 9a49fe6..274f568 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -24,7 +24,6 @@ def sortable_attributes_and_methods( sortable ) end def validate_params(sortable, params) - puts "params[:order] = #{params[:order].inspect}\n\nsortable_attributes_and_methods( sortable ) = #{sortable_attributes_and_methods( sortable ).inspect}\n\n" raise ParameterError.new("#{sortable} has no column or sortable_method \"#{params[:sort_by]}\". \n\nIf you're trying to sort by an instance method that isn't a column name (e.g. a value from an associated table), you must define \n\n\tsortable_instance_methods :my_method_1, :my_method_2 \n\nin your model class. Don't forget to include it as a column in your query too!") unless SortableColumns.sortable_attributes_and_methods(sortable).include?(params[:sort_by].to_s) raise ParameterError.new("Order must be \"asc\" or \"desc\" - you gave #{params[:order]}") unless params[:order].blank? || ["asc","desc"].include?(params[:order].to_s.downcase) end From 5758b9c4801640dbc43fad70e73bde67beb9186e Mon Sep 17 00:00:00 2001 From: Al Davidson Date: Thu, 3 Nov 2011 12:02:40 +0000 Subject: [PATCH 8/8] no longer deletes sort_by and order from params in the sortable_order call - this enables a view template to interrogate those params and e.g. display appropriate icons --- lib/sortable_columns.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sortable_columns.rb b/lib/sortable_columns.rb index 274f568..43a1bb4 100644 --- a/lib/sortable_columns.rb +++ b/lib/sortable_columns.rb @@ -6,7 +6,7 @@ def sortable_order(sortable, options = {}) if params[:sort_by] && params[:order] validate_params(sortable, params) store_sort(sortable) - return "#{params.delete(:sort_by)} #{params.delete(:order)}" + return "#{params[:sort_by]} #{params[:order]}" else if session[:sortable_columns] && session[:sortable_columns][sortable.to_s.downcase.to_sym] column = session[:sortable_columns][sortable.to_s.downcase.to_sym].keys.first