Rails: change URL response format - ruby-on-rails

How to easily change the format of URL in a right way:
/comment/10.js?param1=6
to
/comment/10?param1=6
Preferrably with some URL library or so, not with regexps.
Use case: redirect back with request.request_uri saved in session.

I'm not quite sure the use case, but the simplest way would be in the controller
respond_to do |f|
f.js { redirect_to #copy url params, but set :format to what you actually want }
end

Related

Replace GET params in redirect_to request.referer

I'm trying to Replace GET params in:
redirect_to request.referer
My request.referer already contains one parameter:
http://www.foo.com/bar?par=10
When i try:
redirect_to request.referer, :par => 5
it doesn't work. It redirects to referer but doesn't change :par from 10 to 5.
When i do redirect to url_path, e.g.
redirect_to root_path, :par => 5
This works ok, redirects to:
http://www.foo.com/?par=5
So my question is how to replace params in request.referer URI. Additional question is whether should I use request.referer or :back ?
Thanks
The problem is that redirect_to ultimately just takes a string, ie the url. If you were to do something like
redirect_to edit_foo_path(#foo, :bar => "qux")
then you're using a path helper to generate that string. ie, edit_foo_path(:bar => "qux") is the helper and it will be converted to "/foo/123/edit?bar=qux" which is just a "dumb" string. If you were working with the helper you can switch the params around but with the string it's already finished, if you know what i mean.
request.referer is a string as well, so what you'll need to do is to break it down into its constituent parts, modify those parts as required, and then reassemble it into a string again. The parts in question are protocol, host, path & params. You don't need to change the protocol, host or path in this case so you can keep them the same. params will be most easily manipulated when converted to a hash. Rails has various url-processing functions which you can use here, so there's probably a few different ways of doing this. I would do this like follows, which probably isn't the most efficient.
url = URL(request.referer)
#you could get this via a regex but i'm doing it "formally" with the Url object
host_and_path = "#{url.scheme}://#{url.host}#{url.path}"
params = CGI.parse(url.query)
#now you've got params as a hash you can do what you want to it.
params["par"] = 5
new_url = "#{host_and_path}?#{params.to_param}"
redirect_to new_url
like i say there's probably more efficient (in terms of lines of code, there's no issues with it speed-wise) ways to do this, but it's useful to see the step-by-step approach anyway i guess.

How to trigger download with Rails send_data from AJAX post

I'm trying to use send_data to return a PNG image as the response for a ajax post request. How do I get the browser to trigger a download on the success callback?
Details
I'm generating a large base64 image using canvas.toDataURL(), and then posting it to Rails (v3.2.6). Rails decodes it to a binary PNG, and sends the image back to the client.
I've also tried send_file but it has the same issue.
Other options
Download image client side: We can't do this because (1) Safari crashes on large base64 URLs, and (2) Safari does not yet support the download attribute on anchor tags which I would need to specify the downloaded image filename.
Use a $.get instead of $.post: We can't do this because we need to send our canvas.toDataURL() with the request to the server. GET requests URIs have size limitations.
create a function in controller
def ajax_download
send_file "path_to_file/" + params[:file]
end
and then in controller action
respond_to do |format|
#java_url = "/home/ajax_download?file=#{file_name}"
format.js {render :partial => "downloadFile"}
end
and make a partial in view folder name with _downloadFile.js.erb and write this line
window.location.href = "<%=#java_url %>"
You can't download a file to disk from JS. It's a security concern. See the blog post below for a good workaround.
http://johnculviner.com/post/2012/03/22/Ajax-like-feature-rich-file-downloads-with-jQuery-File-Download.aspx
Do not just copy and paste the accepted answer. It is a massive security risk that cannot be understated. Although the technique is clever, delivering a file based on a parameter anybody can enter allows access to any file anybody can imagine is lying around.
Here's an example of a more secure way to use the same technique. It assumes there is a user logged in who has an API token, but you should be able to adapt it to your own scenario.
In the action:
current_user.pending_download = file_name
current_user.save!
respond_to do |format|
#java_url = "/ajax_download?token=#{current_user.api_token}"
format.js {render :partial => "downloadFile"}
end
Create a function in the controller
def ajax_download
if params[:token] == current_user.api_token
send_file "path_to_file/" + current_user.pending_download
current_user.pending_download = ''
current_user.save!
else
redirect_to root_path, notice: "Unauthorized"
end
end
Make a partial in view folder name with _downloadFile.js.erb
window.location.href = "<%=#java_url %>"
And of course you will need a route that points to /ajax_download in routes.rb
get 'ajax_download', to: 'controller#ajax_download'

How to change the response format depending on the data sent?

I'm doing some controllers to render reports and here is my problem:
The user open a page with a form which let it change the download format and the date of the report.
The download format is set trough a select input.
When the user press the button I want to response depending on the selected format.
The problem is that it's specified trough the url. So trying to do something like:
case format
when "xlsx" then format.xlsx{...}
when "html" then format.html{...}
...
end
doesn't work because rails or the browser (I'm not sure) expects an html response.
I've though of two options:
Change the url of the form onsubmit which makes the application more dependent on javascript. Or.
redirect_to url + ".#{params[:download_format]}"
The second way looks better to me but I need to pass the :report_date in the url and I can't find the way to do it.
I've tried this:
url = my_custom_url_path
redirect_to url + ".#{params[:download_format]}", :date_format => params[:date_format]
But it's not working.
In the form:
<%= f.select :download_format, { "xlsx" => "xlsx, "Online" => "html" } %>
In the controller:
def action
if download_format = params[:download_format].delete
redirect_to my_action_path(options.merge( :format => download_format ) ) and return
end
# do some logic here
respond_to do |format|
format.xlsx{...}
format.html{...}
end
end

Rails redirect_to with params

I want to pass parameters (a hash) to redirect_to, how to do this? For example:
hash = { :parm1 => "hi", :parm2 => "hi" }
and I want to redirect to page /hello
URL like this: /hello?parm1=hi&parm2=hi
If you don't have a named route for /hello then you'll have to hardcode the params into the string that you pass to redirect_to.
But if you had something like hello_path then you could use redirect_to hello_path(:param1 => 1, :param2 => 2)
Instead of:
redirect_to some_params
You can do:
redirect_to url_for(some_params)
You're turning the params into a url with url_for before passing it to redirect_to, so what you pass redirect_to ends up being a URL as a string, which redirect_to is happy to redirect to.
Note well: I don't understand why redirect_to refuses to use params. It used to be willing to use params. At some points someone added something to Rails to forbid it. It makes me suspect that there are security reasons for doing so, and if so, these security reasons could mean that manually doing redirect_to url_for(p) has security implications too. But I haven't yet been able to find any documentation explaining what's up here.
update: I've found the security warning, but haven't digested it yet: https://github.com/rails/rails/pull/16170
The easiest way (if it's not a named route) will be:
redirect_to "/hello?#{hash.to_param}"
See: http://apidock.com/rails/Hash/to_param
Simply, pass the hash into an argument in the URL, and in your code parse it to get out all needed values.
param_arr = []
hash.each do |key , val|
param_arr << "#{key}=#{val}"
end
params_str = param_arr.join("&")
redirect_to "http://somesite.com/somepage?#{params_str}"
I know this might be very basic way to do it, but hey, it'll get you somewhere :)

Rails 3 change path to url

I am passing a path as a parameter, so params[:path] would be name_path(:username => #user.name (I want to pass it as a path and not a url, so putting name_url in the params isn't what I want).
Since you can only use redirect_to with a url, I need to change the path to a url before I can use redirect_to. How would I do this?
I found this method here
def path_to_url(path)
"http://#{request.host_with_port_without_standard_port_handling}/#{path.sub(%r[^/],'')}"
end
But, this was written in 2008, and I want to know if there is a better way in Rails 3?
Updated copy from original path to url post btw: also works on Rails 2
# abs or /abs -> http://myx.com/abs
# http://grosser.it/2008/11/24/rails-transform-path-to-url
def path_to_url(path)
"#{request.protocol}#{request.host_with_port.sub(/:80$/,"")}/#{path.sub(/^\//,"")}"
end
I think you can use a redirect_to with a path as long as its a route defined in the routes file for the current application. Thats seems to be the case from your question.
ie, name_path(:username => #user.name)
So the following should be valid.
redirect_to params[:path]
I ended up using
def path_to_url(path)
"http://#{request.host}/#{path.sub(%r[^/],'')}"
end

Resources