Rails: get params from a string - ruby-on-rails

Say I have a string that is a url with params in it:
http://www.google.com/search?hl=en&client=firefox-a&hs=zlX&rls=org.mozilla%3Aen-US%3Aofficial&q=something&cts=1279154269301&aq=f&aqi=&aql=&oq=&gs_rfai=
How can can I form an array of all the params from the string? I'm aware of the params array that you can access but I'm talking about just any arbitrary string, not one part of the request.

Not sure if there is a rails shortcut, but:
url = 'http://www.google.com/search?hl=en&client=firefox-a&hs=zlX&rls=org.mozilla%3Aen-US%3Aofficial&q=something&cts=1279154269301&aq=f&aqi=&aql=&oq=&gs_rfai='
params = CGI.parse(URI.parse(url).query)
#=> {"hs"=>["zlX"], "oq"=>[""], "cts"=>["1279154269301"], "aqi"=>[""], "rls"=>["org.mozilla:en-US:official"], "hl"=>["en"], "aq"=>["f"], "gs_rfai"=>[""], "aql"=>[""], "q"=>["something"], "client"=>["firefox-a"]}
params = CGI.parse(url)
is almost there gives you:
#=> {"hs"=>["zlX"], "oq"=>[""], "cts"=>["1279154269301"], "aqi"=>[""], "rls"=>["org.mozilla:en-US:official"], "aq"=>["f"], "http://www.google.com/search?hl"=>["en"], "gs_rfai"=>[""], "aql"=>[""], "q"=>["something"], "client"=>["firefox-a"]}

Related

How can I selectively add query parameters in redirect_to?

In my application, the session hash can contain the keys sort and ratings (in addition to _csrf_token and session_id), depending on what action a user takes. That is, it can contain both of them, either one of them, or neither, depending on what a user does.
Now, I wish to call redirect_to in my application and, at the same time, restore any session information (sort or ratings) the user may have provided.
To do this, I want to insert whatever key-value session has currently got stored (out of sort and ratings) as query parameters in my call to redirect_to. So, the path might look something like /movies?sort=...&ratings=....
I don't know how to write the logic for this. How can I do this? And how do I go about selectively inserting query parameters while calling redirect_to? Is it even possible to do this?
Any help is greatly appreciated. Thank you in advance.
First just compose a hash containing the parameters you want - for example:
opts = session.slice(:sort, :ratings)
.merge(params.slice(:sort, :ratings))
.compact_blank
This example would contain the keys :sort, :ratings with the same keys from the parameters merged on top (taking priority).
You can then pass the hash to the desired path helper:
redirect_to foos_path(**opts)
You can either just pass a trailing hash option or use the params option to explitly set the query string:
irb(main):007:0> app.root_path(**{ sort: 'backwards' })
=> "/?sort=backwards"
irb(main):008:0> app.root_path(params: { ratings: 'XX' })
=> "/?ratings=XX"
irb(main):009:0> app.root_path(params: { })
=> "/"
An empty hash will be ignored.
If your calling redirect_to with a hash instead of a string you can add query string parameters with the params: key:
redirect_to { action: :foo, params: opts }
If you're working with an arbitrary given URL/path and want to manipulate the query string parameters you can use the URI module together with the utilities provided by Rack and ActiveSupport for converting query strings to hashes and vice versa:
uri = URI.parse('/foo?bar=1&baz=2&boo=3')
parsed_query = Rack::Utils.parse_nested_query(uri.query)
uri.query = parsed_query.except("baz").merge(x: 5).to_query
puts uri.to_s # => "/foo?bar=1&boo=3&x=5"

How to pass an array of arrays in GET API in Ruby on Rails

I am using a GET API, currently passing an array as a string:
def fetch_details ids
url = "#{url}/api/v1/get-info?ids=#{ids.join(',')}"
response = Net::HTTP.get_response(URI.parse(URI.encode(url)))
if response.code.to_i == 200
return Oj.load(response.body)
else
return {}
end
end
On the server-side I am extracting id from this method:
def self.get_details(ids)
ids = ids.split(",").map {|x| x.gsub( " ", "")}
end
For each id, I want to send an array of UUIDs:
ids = [100,21,301]
uuids= {["abc","bca"],["Xyz"],["pqr","345"]}
Something like this
hash=[
100=>[abc,bca],
21=>[xyz],
301=>[pqr,345]
]
The endpoint uses the id and corresponding UUIDs to join two tables in database query so I should be able to extract the id and corresponding UUID at the end.
How do I pass both these values?
To pass an array in the parameters in Rails/Rack you need to add brackets to the name and repeat the parameter:
/api/v1/get-info?ids[]=1&ids[]=2&ids[]=3
You can use Hash#to_query from ActiveSupport to generate the query string:
irb(main):001:0> { ids: [1,2,3] }.to_query
=> "ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3"
As pointed out by #3limin4t0r you should only use this for one-dimensional arrays of simple values like strings and numbers.
To pass a hash you use brackets but with keys in the brackets:
/api/v1/get-info?foo[bar]=1&foo[baz]=2
Again you can generate the query string with #to_query:
irb(main):002:0> { foo: { bar: 1, baz: 2 } }.to_query
=> "foo%5Bbar%5D=1&foo%5Bbaz%5D=2"
The keys can actually be numbers as well and that should be used to pass complex structures like multidimensional arrays or an array of hashes.

Is it possible to whitelist JSON (as text) in Rails' strong parameters?

Let's say I have this JSON:
{
name: 'David',
tags: {
is_confused: true
}
}
and in a certain model (i.e. User), I can save this directly... but my tags object needs to be saved in a Text column which will later serialize to JSON. Is there any way to do this with strong parameters?
You can force tags to json before permitting it as a string with strong parameters.
Assuming your object is named "params":
params[:tags] = params[:tags].permit(:is_confused).to_json
final_data = params.permit(:name, :tags)
This uses strong parameters to check the tags field before turning it to a json string so that you can save it as text (and use strong parameters to ensure that it's a string).

rails params hash to String:String hash

I am doing an http get using the url http://localhost/add?add_key[0][key]=1234&add_key[0][id]=1.
I have a rails app which gives me a neat params hash {"add_key"=>{"0"=>{"key"=>"1234", "id"=>"1"}}. However when I try to post this to a different server using
new_uri = URI.parse("http://10.10.12.1/test")
res = Net::HTTP.post_form new_uri,params
The server handling the post is seeing this parameter in the request
{"add_key"=>"0key1234id1"}
Looks like post_form requires a String to String hash. So how do I convert the params hash to
{"add_key[0][key]" => "1234", add_key[0][id]" => "1"}
From the fine manual:
post_form(url, params)
Posts HTML form data to the specified URI object. The form data must be provided as a Hash mapping from String to String.
So you're right about what params needs to be.
You could grab the parsed params in your controller:
{"add_key"=>{"0"=>{"key"=>"1234", "id"=>"1"}}
and then recursively pack that back to the flattened format that post_form expects but that would be a lot of pointless busy work. An easy way to do this would be to grab the raw URL and parse it yourself with URI.parse and CGI.parse, something like this in your controller:
u = URI.parse(request.url)
p = CGI.parse(u.query)
That will leave you with {"add_key[0][key]" => "1234", "add_key[0][id]" => "1"} in p and then you can hand that p to Net::HTTP.post_form.

How to use #{} without converting array to string

I have this code block.
query = ['an','array']
#a = params[:action] == 'show' ? "paid" : "paid_students"
variable = "Student.#{#a}(#{query})"
eval(a)
But when I run this I am getting "variable" value as
Student.paid('anarray')
The array is converted to string.How can I avoid this. pls help
The #{} symbol is string interpolation. Its entire purpose is to turn an object into a string and interpolate it into another string. If you want to turn it into a different kind of string, you can certainly do that. For example, if you want to turn it into the string "[1, 2, 3]", you can do variable = "Student.#{#a}(#{query.inspect})".
But a better way to do what you're trying to do would be this:
query = ['an','array']
#a = params[:action] == 'show' ? :paid : :paid_students
Student.send(#a, query)
For more information, see the Ruby Object#send documentation.
variable = "Student.#{#a}(query)"
Doesn't work?

Resources