Vincent
Vincent

Reputation: 16216

Rails: Preserving GET query string parameters in link_to

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?

Upvotes: 50

Views: 31212

Answers (8)

Vincent
Vincent

Reputation: 16216

link_to 'Link', request.query_parameters.merge({:per_page => 20})

Upvotes: 75

Clemens
Clemens

Reputation: 649

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.

Upvotes: 19

Greg Funtusov
Greg Funtusov

Reputation: 1447

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) %>

Upvotes: 4

Joe Van Dyk
Joe Van Dyk

Reputation: 6950

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

Upvotes: 2

complistic
complistic

Reputation: 2710

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

Upvotes: 0

Olek
Olek

Reputation: 274

link_to 'Link', params.merge({:per_page => 20})

Upvotes: 22

jordinl
jordinl

Reputation: 5239

What about

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

?

Upvotes: 1

Reactormonk
Reactormonk

Reputation: 21700

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

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

Upvotes: 2

Related Questions