17

Using rails 2. I want a link to the current page (whatever it is) that keeps all of the params the same but changes the format to 'csv'. (setting the format can be done by having format=csv in the params or by putting .csv at the end of the path). Eg

posts/1
=> posts/1.csv OR posts/1?format=csv
posts?name=jim 
=> posts.csv?name=jim OR posts?name=jim&format=csv 

I tried this as a hacky attempt

request.url+"&format=csv"

and that works fine if there are params in the current url (case 2 above) but breaks if there aren't (case 1). I could come up with more hacky stuff along these lines, eg testing if the request has params, but i'm thinking there must be a nicer way.

cheers, max

EDIT - btw, it's not guaranteed that the current page could have a named route associated with it, in case that's relevant: we could have got there via the generic "/:controller/:action/:id" route.

Max Williams
  • 32,435
  • 31
  • 130
  • 197

3 Answers3

25
<%= link_to "This page in CSV", {:format => :csv } %>
<%= link_to "This page in PDF", {:format => :pdf } %>
<%= link_to "This page in JPEG", {:format => :jpeg } %>

EDIT

Add helper

def current_url(new_params)
  url_for :params => params.merge(new_params)
end

then use this

<%= link_to "This page in CSV", current_url(:format => :csv ) %>

EDIT 2

Or improve your hack:

def current_url(new_params)
  params.merge!(new_params)
  string = params.map{ |k,v| "#{k}=#{v}" }.join("&")
  request.uri.split("?")[0] + "?" + string
end

EDIT

IMPORTANT! @floor - your approach above has a serious problem - it directly modifies params, so if you've got anything after a call to this method which uses params (such as will_paginate links for example) then that will get the modified version which you used to build your link. I changed it to call .dup on params and then modify the duplicated object rather than modifying params directly. – @Max Williams

fl00r
  • 82,987
  • 33
  • 217
  • 237
  • doh, actually, that's no good :( It changes "/music_service_admin/schools" to "/music_service_admin/schools/index.csv". While index is the right action, that url doesn't work because the route interpreter thinks that "index" is an id and goes to the show action. – Max Williams May 06 '11 at 15:43
  • EDIT 1 suffers from the same problem, ie /resources => /resources/index.csv – Max Williams May 06 '11 at 16:24
  • 3
    IMPORTANT! @floor - your approach above has a serious problem - it directly modifies params, so if you've got anything after a call to this method which uses params (such as will_paginate links for example) then that will get the modified version which you used to build your link. I changed it to call .dup on params and then modify the duplicated object rather than modifying params directly. – Max Williams May 12 '11 at 09:29
  • 1
    This works better using `request.query_parameters` rather than `params` to obtain the parameters, because `params` includes the `controller` and `page` parameters too.. – Rahul Sekhar Mar 12 '12 at 08:52
  • This can be insecure as `params` are user input. I believe that on Rails 5 this actually generates an error such as "Attempting to generate a URL from non-sanitized request parameters!" – phylae Apr 12 '18 at 20:46
12

You can use:

link_to "text of link", your_controller_path(format:'csv',params: request.query_parameters)
valdeci
  • 13,962
  • 6
  • 55
  • 80
Oscar García
  • 121
  • 1
  • 3
  • While this code sample may possible answer the question, as it is now it is not very helpful. Please add some explanation to this answer. – oɔɯǝɹ Jan 30 '15 at 12:12
-1

@floor's answer was great, I found it very useful.

Although the method can be improved by using the to_params method rather than contructing your own, like so:

def current_url(new_params)
  params.merge!(new_params)
  "#{request.uri}#{params.to_params}"
end
Mario Visic
  • 2,653
  • 1
  • 22
  • 29