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?

Vincent
  • 16,086
  • 18
  • 67
  • 73

8 Answers8

75
link_to 'Link', request.query_parameters.merge({:per_page => 20})
Simon B.
  • 2,530
  • 24
  • 30
Vincent
  • 16,086
  • 18
  • 67
  • 73
22
link_to 'Link', params.merge({:per_page => 20})
Olek
  • 274
  • 1
  • 3
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.

Clemens
  • 619
  • 6
  • 10
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) %>
Greg Funtusov
  • 1,377
  • 15
  • 18
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
Joe Van Dyk
  • 6,828
  • 8
  • 57
  • 73
2

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

link_to "some_other_link", "/search", :page => params[:page]
Reactormonk
  • 21,472
  • 14
  • 74
  • 123
1

What about

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

?

jordinl
  • 5,219
  • 1
  • 24
  • 20
  • 1
    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. – Vincent Sep 21 '10 at 19:14
  • 1
    What is the rails 3.2+ way to do this? – coudron Jun 26 '13 at 06:30
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
complistic
  • 2,610
  • 1
  • 29
  • 37