50

I have a typical search facility in my app which returns a list of results that can be paginated, sorted, viewed with a different records_per_page value, etc. Each of these options is controlled by parameters in the query string. A simplified example:

/search?q=test&page=2

Now say I need to display a set of links that set records_per_page value to 10, 20, 30. Each link must include the existing query parameters, which can be a very long set, plus a new per_page parameter.

/search?q=test&page=2& ... &per_page=10
/search?q=test&page=2& ... &per_page=20
/search?q=test&page=2& ... &per_page=30

Is there an easy way to do it with just link_to helper or I need to parse and reproduce the query string from previous request somehow?

1

8 Answers 8

75
link_to 'Link', request.query_parameters.merge({:per_page => 20})
Sign up to request clarification or add additional context in comments.

3 Comments

This adds some 'extra' parameters like controller and action.
But you can avoid that by using request.query_parameters instead of request.parameters
use deep_merge if your query parameters require associated arrays or nested hash
22
link_to 'Link', params.merge({:per_page => 20})

Comments

19

The simplest way to merge the new params with the query parameters and NOT with all parameters (including those obtained through the path) is to merge with request.query_parameters

link_to 'Search', search_path(request.query_parameters.merge({ per_page: 20 }))

Otherwise you end up with query strings duplicating the path parameters, for example ?action=index&controller=products&foo=bar instead of ?foo=bar.

Comments

4

If you want to keep existing params and not expose yourself to XSS attacks, be sure to clean the params hash, leaving only the params that your app can be sending:

# inline
<%= link_to 'Link', params.slice(:sort).merge(per_page: 20) %>

 

If you use it in multiple places, clean the params in the controller:

# your_controller.rb
@params = params.slice(:sort, :per_page)

# view
<%= link_to 'Link', @params.merge(per_page: 20) %>

Comments

2

You can just throw elements of the params hash at link_to. Like

link_to "some_other_link", "/search", :page => params[:page]

Comments

2

This works if the links you are processing aren't given to you by request.params.

require 'rack/utils'                                                                                
require 'uri'                                                                                       

def modify_query url, options={}                                                                    
  uri = URI(url)                                                                                    
  query_hash = Rack::Utils.parse_query(uri.query)                                                   
  query_hash.merge!(options)                                                                        
  uri.query = Rack::Utils.build_query(query_hash)                                                   
  uri.to_s                                                                                          
end                                                                                                 

puts modify_query('/search?q=test&page=2&per_page=10', 'per_page' =>  20)                           
puts modify_query('/search?q=test&page=2', 'per_page' => 30)                                        

# Outputs                                                                                           
# /search?q=test&page=2&per_page=20                                                                 
# /search?q=test&page=2&per_page=30

Comments

1

What about

<%= link_to 'Whatever', :overwrite_params => { :pear_page => 20 } %>

?

2 Comments

This looks just like what I was looking for. However it's deprecated in Rails 3. link_to 'link', request.parameters.merge({:per_page => 20}) worked for me.
What is the rails 3.2+ way to do this?
0

A bit late i know..

If your using this as a way to filter search results have a look at my helper :)

This automagicly removes all blank and unneeded params and add the class "selected" if all of it's new params were already set.

def search_to s, args={}

  selected = 0
  args.each do |k, v|
    selected = selected + 1 if params[k] == v.to_s || ( params[k].nil? && v.blank? )
  end

  if @search_params_base.nil?
    @search_params_base = request.parameters.clone
    @search_params_base.delete(:action)
    @search_params_base.delete(:controller)
    @search_params_base.delete(:page)
    @search_params_base.delete_if{|k, v| v.nil? || v.blank?}
    @search_params_base.delete(:utf8) if @search_params_base[:keywords].nil?
  end
  search_params = @search_params_base.merge(args)
  search_params.delete_if{|k, v| v.nil? || v.blank?}

  link_to s, search_path + '?' + search_params.to_param, :class => selected == args.length ? 'selected' : nil
end

You can then just use this in your view:

search_to '$80 to $110', :price => 80..110

Or in your case:

search_to '30 per page', :page => params[:page], :per_page => 30

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.