Rails 3 question.
If i send a request like this PUT http://myapp/posts/123?post[title]=hello
then in my controller i get params = {:id => 123, :post => {:title => "hello"}}
This is fine normally and usually useful for eg Post.create(params[:post])
However, on this occasion i need to get access to the 'raw' form of the params so i can order them pull out the values, dealing with them all as simple strings, ie i want them listed so the param name is "post[title]" and the param value is "hello".
Is there any way i get get these values? I thought there might be a method of request that has the params in their original stringy form but i can't find one.
It had occurred to me to try to convert the hash back into a string with to_param but this seems a but dirty and possibly unecessary.
As a bonus, i'd like it to ignore the :id parameter, literally just taking the part after the ? in the original request. In fact, if i can just get back the original request string, ie "http://myapp/posts/123?post[title]=hello" then that would do: i could split on the ? and take it from there. It just occurred to me that i can probably get it out of a header. In the meantime though, if anyone knows a nicer way then tell me please :)
Grateful for any advice - max
Don't do the parsing by hand, please. Grab the URI from the Rails request:
url = request.url
# Or, depending on the Rails version and stack
url = request.request_uri
# Or even
url = request.scheme + '://' + request.host_with_port + request.fullpath
The return value from request.url seems to depend on your server stack, request.request_uri is supposed to fix that but doesn't seem to exist in Rails 3.1. The third "build it all yourself" approach should produce consistent results everywhere. Sigh.
Then, once you have the URI, use URI.parse and URI.decode_www_form to parse it:
u = URI.parse(url)
q = URI.decode_www_form(u.query)
# if u.query was "a=b&c=d&a=x" then q is
# [["a", "b"], ["c", "d"], ["a", "x"]]
Request#body and Request#uri should help you. You can get the "raw" request data, but not some intermediate form... though it's not that hard to just split at the ampersands and then again at the "=" if you want key-value pairs ;)
Related
I am sending this request to a service:
get_store_data = Typhoeus::Request.new("http://localhost:3000/api/v1/store?service=#{(proxy_ticket.service)}&ticket=#{proxy_ticket.ticket}")
proxy_ticket.service resolves to this string "http://localhost:3000/api/v1/store". When the request is sent, This string is escaped to this:
service=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fv1%2Fstore
The problem is that the service on the other end expects the service parameter as "http://localhost:3000/api/v1/store" how can i prevent this query string from being escaped?
The other side should be unescaping the params. If you would still like to know how to do it however here is the method uri.unescape which is used like so:
require 'uri'
enc_uri = URI.escape("http://example.com/?a=\11\15")
p enc_uri
# => "http://example.com/?a=%09%0D"
p URI.unescape(enc_uri)
# => "http://example.com/?a=\t\r"
If you ever want to quickly unescape a uri (and don't want to open a repl for some strange reason or other, like maybe it insulted your honour or something.) you can try this site
You can't. Its the 'other side' who should decode this param (and most likely they do).
For example rails do this encoding automatically. You can check it by altering some of your actions to raise params.pretty_inspect and invoke it with extra param your/action/route?service=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fv1%2Fstore. You will see that params include service: http://localhost:3000/api/v1/store.
If this is not working for you this mine that you need to get in touch with the other side so they implement this. There is no other way to pass urls within get urls.
In my database i store urls as string, with protocol validation, meaning there has to be a "http://", "https://" or "ftp://" before hostname.
Also, to my controller action POST request is being sent, but just with hostname, no protocol. How can I search database for this hostname?
The easiest solution would be to just construct new string with protocol, but i dont know which one i'm going to need. It might be "https" just as well as "http".
Any ideas?
(NOTE: This is Rails 3 app)
EDIT
It's been pointed out that my question is not clear, so I will try to explain it better now.
In database i have column url. It stores links which begin with "http://", "https://" or "ftp://".
they may look like this:
url:
"http://google.com"
"https://amazon.com"
"ftp://somehostname.com"
My controller gets POST request with hostname, it may be {"domain" => "google.com"}
So now what i need to do is search the database for "google.com" to update it. BUT as you can see, value under "domain" key doesnt store protocol. So i dont know if it is "http://google.com" or "https://google.com", yet i must somehow find it.
request.host
request.host_with_port
request.url
request.host
The just query with .where(:url => current_url)
Not exactly sure what you're asking but these should point you in the right direction (I hope)
From what I understand you are going to get a URL without the protocol in one of your POST params and you want to match it with the ones in your database which HAVE a protocol.
This is what I would do:
Option 1:
If feasible store the protocol and rest of the URL in two separate fields in the database. Easy to compare that way.
Option 2:
Use regular expressions!
Let's say you get params as follows:
{"domain" => "google.com"}
I would then do this to find the record:
(Assuming name of your model is "Record")
domain = params[:domain]
#record = Record.where('name = ? OR name = ? OR name = ?', "https://#{domain}", "http://#{domain}", "ftp://#{domain}" )
I can't work this out.
url = "www.mysite.com/?param1=abc"
redirect_to(url, :param2 => 'xyz')
### Should this go to - www.mysite.com/?param1=abc¶m2=xyz
Or am I missing something? It doesn't seem to work?
From the documentation:
redirect_to(options = {}, response_status = {})
Redirects the browser to the target specified in options. This
parameter can take one of three forms:
Hash - The URL will be generated by calling url_for with the options.
Record - The URL will be generated by calling url_for with the
options, which will reference a named URL for that record.
String starting with protocol:// (like http://) or a protocol relative
reference (like //) - Is passed straight through as the target for
redirection.
You're passing a String as the first argument, so it's using the 3rd option. Your second parameter is interpreted as the value for the response_status parameter.
So, if your redirect is an internal one (to the same app), you don't need to specify the scheme and hostname. Just use
redirect_to root_url(param1 => 'abc', param2 => 'xyz')
If it's an external URL, build the complete URL before redirecting:
url = "www.mysite.com/?param1=abc¶ms2=xyz"
redirect_to url
redirect_to is not a Ruby function but is commonly used in Ruby on Rails. You can find its documentation with a lot of working examples here.
If you want to open a website within plain Ruby, use the 'open-uri' class. You can find its documentation here.
I hope this helps understanding why redirect_to doesn't work in plain Ruby and might help using it with and without Rails.
it won't know about the old params unless you merge them in and send them on.
url = "www.mysite.com/?param1=abc"
p = params.merge({:param2 => 'xyz'})
redirect_to(url, p)
I am using Ruby on Rails 3.1.0 and I would like to know what is a common practice to prevent to store "malicious" values in the database.
For example, I have a database table column means to store URLs. A user, passing the validation (just a length check), can submit a URL like http://<script>alert('hello!');</script>. I would like to do not permit to store links like the above... how can I make that?
The proper thing to do is use URI to parse the supposed URL and then check each component:
validate :url_check
def url_check
u = URI.parse(self.url)
# check u.scheme, u.userinfo, etc. and call errors.add(:url, '...')
# if something is invalid.
rescue URI::InvalidURIError
errors.add(:url, 'You are being naughty.')
end
While those links are in the database, they do no harm. Problems might occur when you try to render them. Rails does a good job in escaping most things that you output (I didn't dare to say "everything", 'cause I don't know for sure).
You can be extra sure and escape a string yourself:
CGI.escape your_link_url
Link: CGI.escape
You can use regex to validate it's a valid url without the '<', '>' url. And HTML encode it where it applies.
With overwrite_params, I was doing this to prepare a PDF request for a page:
url_for(:overwrite_params => {:format => :pdf})
overwrite_params has been deprecated after Rails 2.3.8, is there a reason for this deprecation? What's the standard accepted alternative?
This is what your looking for:
url_for params.merge(:format => "PDF", :only_path => false)
This will create an absolute url for the current page including the current params.
Note that the suggested solution of merging with params is not correct as it also contains data from the request body (sometimes misleadingly referred to as POST variables). A better (the correct?) solution is to merge with request.GET instead (another misnomer as e.g. POST requests obviously may contain query parameters, too).
Using overwrite_params is allowing you to make mistakes and bad design - you are not protected from overwriting params in urls which are not relevant to your call.
It is much better aways know what is coming. Keep your params in a bean/model and serialize this bean to url.
If you want to break the rules of the good design you can aways do it yourself(with the .merge option) but then it is your responsibility.
I am guessing they deprecated the method to simplify it, so you just have to pass in the parameters you want to overwrite, instead of writing :overwrite_params. It makes sense that this method should overwrite the parameters by default.. if you are specifying parameters you obviously want to use the specified values instead of the existing.
You should be able to do it like this instead:
url_for(:format => :pdf)
A quick test on my users index page returns this:
/users.pdf