diff --git a/README.md b/README.md index cb8541a4b..1b65a1a74 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,23 @@ Ransack.configure do |c| end ``` +####`sort_url` is return only url of `sort_link` + +It can be used like `sort_link`. + +```erb +<%= sort_url(@q, :name, default_order: :desc) %> +``` + +```erb +<%= sort_url(@q, :last_name, [:last_name, 'first_name asc']) %> +``` + +```erb +<%= sort_url(@q, :last_name, %i(last_name first_name), + default_order: { last_name: 'asc', first_name: 'desc' }) %> +``` + ### Advanced Mode "Advanced" searches (ab)use Rails' nested attributes functionality in order to diff --git a/lib/ransack/helpers/form_builder.rb b/lib/ransack/helpers/form_builder.rb index 4ea5e66fc..81d7be7f0 100644 --- a/lib/ransack/helpers/form_builder.rb +++ b/lib/ransack/helpers/form_builder.rb @@ -83,6 +83,10 @@ def sort_link(attribute, *args) @template.sort_link @object, attribute, *args end + def sort_url(attribute, *args) + @template.sort_url @object, attribute, *args + end + def condition_fields(*args, &block) search_fields(:c, args, block) end diff --git a/lib/ransack/helpers/form_helper.rb b/lib/ransack/helpers/form_helper.rb index ea83d6f81..c67547ed1 100644 --- a/lib/ransack/helpers/form_helper.rb +++ b/lib/ransack/helpers/form_helper.rb @@ -54,6 +54,18 @@ def sort_link(search_object, attribute, *args, &block) link_to(s.name, url(routing_proxy, s.url_options), s.html_options(args)) end + # +sort_url+ + # <%= sort_url(@q, :created_at, default_order: :desc) %> + # + def sort_url(search_object, attribute, *args) + search, routing_proxy = extract_search_and_routing_proxy(search_object) + unless Search === search + raise TypeError, 'First argument must be a Ransack::Search!' + end + s = SortLink.new(search, attribute, args, params) + url(routing_proxy, s.url_options) + end + private def options_for(record) diff --git a/spec/ransack/helpers/form_helper_spec.rb b/spec/ransack/helpers/form_helper_spec.rb index fc39fbacc..624a83f4d 100644 --- a/spec/ransack/helpers/form_helper_spec.rb +++ b/spec/ransack/helpers/form_helper_spec.rb @@ -43,6 +43,25 @@ module Helpers it { should match /Full Name ▼/ } end + describe '#sort_url with default search_key' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search(sorts: ['name desc'])], + :name, + controller: 'people' + ) + } + it { + should match( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?q%5Bs%5D=name\+asc/ + else + /people\?q(%5B|\[)s(%5D|\])=name\+asc/ + end + ) + } + end + describe '#sort_link with default search_key defined as symbol' do subject { @controller.view_context .sort_link( @@ -64,6 +83,27 @@ module Helpers } end + describe '#sort_url with default search_key defined as symbol' do + subject { @controller.view_context + .sort_url( + Person.search( + { sorts: ['name desc'] }, search_key: :people_search + ), + :name, + controller: 'people' + ) + } + it { + should match( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?people_search%5Bs%5D=name\+asc/ + else + /people\?people_search(%5B|\[)s(%5D|\])=name\+asc/ + end + ) + } + end + describe '#sort_link desc through association table defined as a symbol' do subject { @controller.view_context .sort_link( @@ -85,6 +125,25 @@ module Helpers it { should match /Body ▲/ } end + describe '#sort_url desc through association table defined as a symbol' do + subject { @controller.view_context + .sort_url( + Person.search({ sorts: 'comments_body asc' }), + :comments_body, + controller: 'people' + ) + } + it { + should match( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?q%5Bs%5D=comments.body\+desc/ + else + /people\?q(%5B|\[)s(%5D|\])=comments.body\+desc/ + end + ) + } + end + describe '#sort_link through association table defined as a string' do subject { @controller.view_context .sort_link( @@ -106,6 +165,25 @@ module Helpers it { should match /Comments.body ▼/ } end + describe '#sort_url through association table defined as a string' do + subject { @controller.view_context + .sort_url( + Person.search({ sorts: 'comments.body desc' }), + 'comments.body', + controller: 'people' + ) + } + it { + should match( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /people\?q%5Bs%5D=comments.body\+asc/ + else + /people\?q(%5B|\[)s(%5D|\])=comments.body\+asc/ + end + ) + } + end + describe '#sort_link works even if search params are a blank string' do before { @controller.view_context.params[:q] = '' } specify { @@ -120,6 +198,20 @@ module Helpers } end + describe '#sort_url works even if search params are a blank string' do + before { @controller.view_context.params[:q] = '' } + specify { + expect { @controller.view_context + .sort_url( + Person.search( + @controller.view_context.params[:q]), + :name, + controller: 'people' + ) + }.not_to raise_error + } + end + describe '#sort_link with search_key defined as a string' do subject { @controller.view_context .sort_link( @@ -153,6 +245,18 @@ module Helpers it { should_not match /default_order/ } end + describe '#sort_url with default_order defined with a string key' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search()], + :name, + controller: 'people', + default_order: 'desc' + ) + } + it { should_not match /default_order/ } + end + describe '#sort_link with multiple search_keys defined as an array' do subject { @controller.view_context .sort_link( @@ -170,6 +274,21 @@ module Helpers it { should match /Full Name ▼/ } end + describe '#sort_url with multiple search_keys defined as an array' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search(sorts: ['name desc', 'email asc'])], + :name, [:name, 'email DESC'], + controller: 'people' + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/ + ) + } + end + describe '#sort_link with multiple search_keys does not break on nil values & ignores them' do subject { @controller.view_context .sort_link( @@ -187,6 +306,21 @@ module Helpers it { should match /Full Name ▼/ } end + describe '#sort_url with multiple search_keys does not break on nil values & ignores them' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search(sorts: ['name desc', nil, 'email', nil])], + :name, [nil, :name, nil, 'email DESC', nil], + controller: 'people' + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/ + ) + } + end + describe '#sort_link with multiple search_keys should allow a label to be specified' do subject { @controller.view_context .sort_link( @@ -216,6 +350,21 @@ module Helpers it { should match /Full Name ▼/ } end + describe '#sort_url with multiple search_keys should flip multiple fields specified without a direction' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search(sorts: ['name desc', 'email asc'])], + :name, [:name, :email], + controller: 'people' + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+asc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/ + ) + } + end + describe '#sort_link with multiple search_keys and default_order specified as a string' do subject { @controller.view_context .sort_link( @@ -234,6 +383,22 @@ module Helpers it { should match /Full Name/ } end + describe '#sort_url with multiple search_keys and default_order specified as a string' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search()], + :name, [:name, :email], + controller: 'people', + default_order: 'desc' + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/ + ) + } + end + describe '#sort_link with multiple search_keys and default_order specified as a symbol' do subject { @controller.view_context .sort_link( @@ -252,6 +417,22 @@ module Helpers it { should match /Full Name/ } end + describe '#sort_url with multiple search_keys and default_order specified as a symbol' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search()], + :name, [:name, :email], + controller: 'people', + default_order: :desc + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/ + ) + } + end + describe '#sort_link with multiple search_keys should allow multiple default_orders to be specified' do subject { @controller.view_context .sort_link( @@ -270,6 +451,22 @@ module Helpers it { should match /Full Name/ } end + describe '#sort_url with multiple search_keys should allow multiple default_orders to be specified' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search()], + :name, [:name, :email], + controller: 'people', + default_order: { name: 'desc', email: 'asc' } + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+asc/ + ) + } + end + describe '#sort_link with multiple search_keys with multiple default_orders should not override a specified order' do subject { @controller.view_context .sort_link( @@ -288,6 +485,22 @@ module Helpers it { should match /Full Name/ } end + describe '#sort_url with multiple search_keys with multiple default_orders should not override a specified order' do + subject { @controller.view_context + .sort_url( + [:main_app, Person.search()], + :name, [:name, 'email desc'], + controller: 'people', + default_order: { name: 'desc', email: 'asc' } + ) + } + it { + should match( + /people\?q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=name\+desc&q(%5B|\[)s(%5D|\])(%5B|\[)(%5D|\])=email\+desc/ + ) + } + end + describe "#sort_link on polymorphic association should preserve association model name case" do subject { @controller.view_context .sort_link( @@ -309,6 +522,25 @@ module Helpers it { should match /Notable/ } end + describe "#sort_url on polymorphic association should preserve association model name case" do + subject { @controller.view_context + .sort_link( + [:main_app, Note.search()], + :notable_of_Person_type_name, "Notable", + controller: 'notes' + ) + } + it { + should match( + if ActiveRecord::VERSION::STRING =~ /^3\.[1-2]\./ + /notes\?q%5Bs%5D=notable_of_Person_type_name\+asc/ + else + /notes\?q(%5B|\[)s(%5D|\])=notable_of_Person_type_name\+asc/ + end + ) + } + end + context 'view has existing parameters' do describe '#sort_link should not remove existing params' do @@ -329,6 +561,24 @@ module Helpers it { should match /exist\=existing/ } end + describe '#sort_url should not remove existing params' do + + before { @controller.view_context.params[:exist] = 'existing' } + + subject { + @controller.view_context.sort_url( + Person.search( + { sorts: ['name desc'] }, + search_key: 'people_search' + ), + :name, + controller: 'people' + ) + } + + it { should match /exist\=existing/ } + end + context 'using a real ActionController::Parameter object', if: ::ActiveRecord::VERSION::MAJOR > 3 do @@ -347,6 +597,21 @@ module Helpers } end + describe 'with symbol q:, #sort_url should include search params' do + subject { @controller.view_context.sort_url(Person.search, :name) } + let(:params) { ActionController::Parameters.new( + { :q => { name_eq: 'TEST' }, controller: 'people' } + ) } + before { @controller.instance_variable_set(:@params, params) } + + it { + should match( + /people\?q(%5B|\[)name_eq(%5D|\])=TEST&q(%5B|\[)s(%5D|\]) + =name\+asc/x, + ) + } + end + describe "with string 'q', #sort_link should include search params" do subject { @controller.view_context.sort_link(Person.search, :name) } let(:params) { @@ -362,6 +627,22 @@ module Helpers ) } end + + describe "with string 'q', #sort_url should include search params" do + subject { @controller.view_context.sort_url(Person.search, :name) } + let(:params) { + ActionController::Parameters.new( + { 'q' => { name_eq: 'Test2' }, controller: 'people' } + ) } + before { @controller.instance_variable_set(:@params, params) } + + it { + should match( + /people\?q(%5B|\[)name_eq(%5D|\])=Test2&q(%5B|\[)s(%5D|\]) + =name\+asc/x, + ) + } + end end end