Initial work on sort_link. Mostly ported from MetaSearch, changes coming soon

This commit is contained in:
Ernie Miller 2011-08-13 16:36:40 -04:00
parent c156fa4a7a
commit f6973b3a3b
6 changed files with 101 additions and 2 deletions

View File

@ -73,6 +73,10 @@ module Ransack
search_fields(:s, args, block)
end
def sort_link(attribute, *args)
@template.sort_link @object, attribute, *args
end
def condition_fields(*args, &block)
search_fields(:c, args, block)
end

View File

@ -1,6 +1,7 @@
module Ransack
module Helpers
module FormHelper
def search_form_for(record, options = {}, &proc)
if record.is_a?(Ransack::Search)
search = record
@ -23,6 +24,52 @@ module Ransack
form_for(record, options, &proc)
end
def sort_link(search, attribute, *args)
raise TypeError, "First argument must be a Ransack::Search!" unless Search === search
search_params = params[:q] || {}.with_indifferent_access
attr_name = attribute.to_s
name = (args.size > 0 && !args.first.is_a?(Hash)) ? args.shift.to_s : Translate.attribute(attr_name, :context => search.context)
if existing_sort = search.sorts.detect {|s| s.name == attr_name}
prev_attr, prev_dir = existing_sort.name, existing_sort.dir
end
options = args.first.is_a?(Hash) ? args.shift.dup : {}
default_order = options.delete :default_order
current_dir = prev_attr == attr_name ? prev_dir : nil
if current_dir
new_dir = current_dir == 'desc' ? 'asc' : 'desc'
else
new_dir = default_order || 'asc'
end
html_options = args.first.is_a?(Hash) ? args.shift.dup : {}
css = ['sort_link', current_dir].compact.join(' ')
html_options[:class] = [css, html_options[:class]].compact.join(' ')
options.merge!(
:q => search_params.merge(:s => "#{attr_name} #{new_dir}")
)
link_to [ERB::Util.h(name), order_indicator_for(current_dir)].compact.join(' ').html_safe,
url_for(options),
html_options
end
private
def order_indicator_for(order)
if order == 'asc'
'▲'
elsif order == 'desc'
'▼'
else
nil
end
end
end
end
end

View File

@ -49,8 +49,10 @@ module Ransack
sort = Nodes::Sort.new(@context).build(attrs)
self.sorts << sort
end
else
when String
self.sorts = [args]
else
raise ArgumentError, "Invalid argument (#{args.class}) supplied to sorts="
end
end
alias :s= :sorts=

View File

@ -12,7 +12,7 @@ module Ransack
def self.attribute(key, options = {})
unless context = options.delete(:context)
raise ArgumentError, "A context is required to translate associations"
raise ArgumentError, "A context is required to translate attributes"
end
original_name = key.to_s

View File

@ -47,6 +47,14 @@ module Ransack
end
describe '#sort_link' do
subject { @f.sort_link :name, :controller => 'people' }
it { should match /people\?q%5Bs%5D=name\+asc/}
it { should match /sort_link/}
it { should match /Full Name<\/a>/}
end
describe '#submit' do
it 'localizes :search when no default value given' do

View File

@ -0,0 +1,38 @@
require 'spec_helper'
module Ransack
module Helpers
describe FormHelper do
router = ActionDispatch::Routing::RouteSet.new
router.draw do
resources :people
match ':controller(/:action(/:id(.:format)))'
end
include router.url_helpers
# FIXME: figure out a cleaner way to get this behavior
before do
@controller = ActionView::TestCase::TestController.new
@controller.instance_variable_set(:@_routes, router)
@controller.class_eval do
include router.url_helpers
end
@controller.view_context_class.class_eval do
include router.url_helpers
end
end
describe '#sort_link' do
subject { @controller.view_context.sort_link(Person.search(:sorts => ['name desc']), :name, :controller => 'people') }
it { should match /people\?q%5Bs%5D=name\+asc/}
it { should match /sort_link desc/}
it { should match /Full Name &#9660;/}
end
end
end
end