I have an ajax response like this ,
google_searched_locations [{"geometry":{"location":{"J":31.482273,"M":74.33069999999998}},"icon":"https://maps.gstatic.com/mapfiles
/place_api/icons/restaurant-71.png","id":"b93a99a46343de01d0d928f99470f9b0f5f6f11d","name":"Dunkin' Donuts"
,"place_id":"ChIJSeoh6hkEGTkRsd0e1crAbHU","rating":4.3,"reference":"CnRhAAAAewgE30hrAcax1xdGPIf7M863
bOtNhRgfnncMx17uWMgtdTyGHGbTO76LX6yXsPyB4PcvfVzIeeIR1bxG0oSambqMYxFWwqHY3Cyfs6uWFp2QbVkGObvQ1LlTrdqLh1eZVgX8aL0iRFFhAnHEM8u1RxIQACDCn2BMD3IiG7tKri31BRoULMSagTU-EmxswgLxzCOWPVVnlpI"
,"scope":"GOOGLE","types":["restaurant","food","point_of_interest","establishment"],"vicinity":"Lahore"
,"html_attributions":[]}]
After JSON.parse(thisString) , I get the required result by using params["places"][0]["geometry"] and then looping over it , but I know that it's not a better way when Rails have strong parameter there , so I tried some solutions after searching , below is my strong parameters function
def google_places
json_params = ActionController::Parameters.new(JSON.parse(request.body.read) )
json_params.require(:google_searched_locations).permit(:icon)
end
but it gives the following error ,
JSON::ParserError in SearchesController#searchResults
757: unexpected token at 'places=%5B%7B%22geometry
Can anyone make us out of this mess , and tell us what's happening here and where is the right way to go .
Thanks in advance :)
You do not need to manually parse JSON parameters. Rails will automatically parse the parameters provided the request has the correct format (more specifically the correct mime type headers). In fact doing so will be slower and use more memory since you are doing the same parsing work twice.
To allow an array of parameters you simply use the hash key and an array of the permitted attributes for the nested params.
def google_places
params.permit(places: [:icon, { location: [:H, :L] }])
end
If possible you should change the H and L parameters to lowercase so that you can map them directly to attributes without violating the ruby conventions of lowercase attributes.
Related
I'm currently trying to understand how permitted parameters works in ruby.
Usually, in my_model.rb I have:
has_many: some_other_model
*
*
*
def my_model_params
params.require(:my_model).permit( :column1, some_other_model_attributes %i[other_column1])
etc...
and in the update function
my_object.update_attributes(my_model_params)
with a well formatted json which has some my_model root, and some_other_model_attributes as a child (array) with values.
My problem is I receive a json like this one
However the different arrays inside (such as codification, general_information) do contain attributes of the mission (general_information contains reference that is a column in the mission table) but there isn't any column named codification, or relation to a codification_attributes.
So, when I add :
general_information: %i[reference] in the permitted params, it says unknown attribute 'general_information' for Mission.
If not, no error are raised but in the log I can see unpermitted_parameter: general_information. And my object is not updated.
Finally if I reject it, there is no more unpermitted_parameter: general_information in the log but my object is not updated either.
I tried to set config.action_controller.action_on_unpermitted_parameters to false in my development config, it did nothing and it's probably a bad idea for production environment anyway.
The use of .permit! (even if it works) is currently not an option. And even though I think the json needs to be re-formatted it'd be better to find an other solution.
Thanks for the help.
unpermitted_parameter: ... in logs in not a problem which you need to fix, it's just an info.
How it works - you just permit needed parameters, you may think about them as a hash. Unpermitted parameters will not go into the model even if they are present in params. It means when you call
my_object.update_attributes(my_model_params)
it works like
my_object.update_attributes(column1: value_for_column1_from_params)
Keys in params should be named exactly as columns in the model, otherwise you need to prepare params somehow before create/update
I'm trying to get the value of a variable, prop, in a query string from a passed URL similar to what the gentleman in this thread did.
It works if there's a query string in the URL but if there isn't I get
CGI.parse undefined method 'split' for nil:NilClass error. I did research and the problem is because there is no query to split.
So my question is how can I test for the presence of any query string and then run it through CGI.parse to see if the prop query string is one of them? I assume I could probably do it through Regex but I was hoping there was a Rails solution.
Any help would be appreciated.
Thanx
Code:
I'm also trying to get the domain name of the URL referrer. That is why I have that variable in there.
url = request.env['HTTP_REFERER']
encoded_url = URI.encode(url.to_s)
parse = URI.parse(encoded_url)
domain = parse.host
puts domain
params = CGI.parse(parse.query)
puts params['prop'].first
UPDATE:
I got the error to go away by adding the attached code. But I'm still wondering if there's a better Rails solution. I'm still fairly new to Rails, so I want to make sure I'm doing it correctly.
if encoded_url.include? "?prop"
params = CGI.parse(parse.query)
puts params['prop'].first
end
The keys in query string in a URL can be accessed using params[] hash, even if the URL is not present inside the app itself. This is how it is convenient for rails to communicate with the outside world as well. Note that rails treats all the HTTP verbs equally when it comes to usage of params[] hash.
Usage: puts params[:your_key]
I am setting up stripe connect with the example from https://github.com/rfunduk/rails-stripe-connect-example and am running into a problem using serialize to store stripe_account_status which should be stored as an array.
This is how it should be stored (Generated from the above example link)
{"details_submitted"=>false, "charges_enabled"=>true, "transfers_enabled"=>false, "fields_needed"=>["legal_entity.first_name", "legal_entity.last_name", "legal_entity.dob.day", "legal_entity.dob.month", "legal_entity.dob.year", "legal_entity.address.line1", "legal_entity.address.city", "legal_entity.address.postal_code", "bank_account"], "due_by"=>nil}
And this is how my application is storing it
{:details_submitted=>false, :charges_enabled=>true, :transfers_enabled=>false, :fields_needed=>["legal_entity.first_name", "legal_entity.last_name", "legal_entity.dob.day", "legal_entity.dob.month", "legal_entity.dob.year", "legal_entity.address.line1", "legal_entity.address.city", "legal_entity.address.postal_code", "bank_account"], :due_by=>nil}
As far as I am concerned everything is set up the same. The only difference is that the first example uses
serialize :stripe_account_status, JSON
and my app just has
serialize :stripe_account_status
The reason for this is that when I add JSON I this error:
JSON::ParserError - 795: unexpected token at '':
I have tried finding out the JSON error including changing the config/initializers/cookies_serializer.rb to use :hybrid but this is giving me the same error.
Could someone point me into the right direction of either fixing the JSON issue OR finding a way to make sure the stripe_account_status is stored as an array correctly.
Below is the methods used to store the array:
if #account
user.update_attributes(
currency: #account.default_currency,
stripe_account_type: 'managed',
stripe_user_id: #account.id,
secret_key: #account.keys.secret,
publishable_key: #account.keys.publishable,
stripe_account_status: account_status
)
end
def account_status
{
details_submitted: account.details_submitted,
charges_enabled: account.charges_enabled,
transfers_enabled: account.transfers_enabled,
fields_needed: account.verification.fields_needed,
due_by: account.verification.due_by
}
end
Thanks I really appreciate any direction you could point me!
When you ask Rails to serialize an attribute on a model, it will default to storing the object as YAML string.
You can ask Rails to serialize differently, as you have noticed by providing a class to do the serialization e.g
serialize :stripe_account_status, JSON
The reason why this isn't working when you add it is because you presumably already have a record in the database using the YAML and so Rails can't parse this as a valid JSON string when reading from the DB. If it's just development data that you don't need, you can delete the records and then use JSON, otherwise you will need to convert the current YAML strings to JSON.
Rails will also symbolize the keys of a hash when parsing a serialized string in the database. This is the only difference between the hashes in your question and shouldn't matter in practise. Should you need String keys for some reason, you can use the #stringify_keys method on the hash provided by Rails.
I have a string like this:
"foo=bar&bar=foo&hello=hi"
Does Ruby on Rails provide methods to parse this as if it is a querystring, so I get a hash like this:
{
:foo => "bar",
:bar => "foo",
:hello => "hi"
}
Or must I write it myself?
EDIT
Please note that the string above is not a real querystring from a URL, but rather a string stored in a cookie from Facebook Connect.
The answer depends on the version of Rails that you are using. If you are using 2.3 or later, use Rack's builtin parser for params
Rack::Utils.parse_nested_query("a=2") #=> {"a" => "2"}
If you are on older Rails, you can indeed use CGI::parse. Note that handling of hashes and arrays differs in subtle ways between modules so you need to verify whether the data you are getting is correct for the method you choose.
You can also include Rack::Utils into your class for shorthand access.
The
CGI::parse("foo=bar&bar=foo&hello=hi")
Gives you
{"foo"=>["bar"], "hello"=>["hi"], "bar"=>["foo"]}
Edit:
As specified by Ryan Long this version accounts for multiple values of the same key, which is useful if you want to parse arrays too.
Edit 2:
As Ben points out, this may not handle arrays well when they are formatted with ruby on rails style array notation.
The rails style array notation is: foo[]=bar&foo[]=nop. That style is indeed handled correctly with Julik's response.
This version will only parse arrays correctly, if you have the params like foo=bar&foo=nop.
Edit : as said in the comments, symolizing keys can bring your server down if someone want to hurt you. I still do it a lot when I work on low profile apps because it makes things easier to work with but I wouldn't do it anymore for high stake apps
Do not forget to symbolize the keys for obtaining the result you want
Rack::Utils.parse_nested_query("a=2&b=tralalala").deep_symbolize_keys
this operation is destructive for duplicates.
If you talking about the Urls that is being used to get data about the parameters them
> request.url
=> "http://localhost:3000/restaurants/lokesh-dhaba?data=some&more=thisIsMore"
Then to get the query parameters. use
> request.query_parameters
=> {"data"=>"some", "more"=>"thisIsMore"}
If you want a hash you can use
Hash[CGI::parse(x).map{|k,v| [k, v.first]}]
I have a URL of form http://www.example.com?foo=one&foo=two
I want to get an array of values ['one', 'two'] for foo, but params[:foo] only returns the first value.
I know that if I used foo[] instead of foo in the URL, then params[:foo] would give me the desired array.
However, I want to avoid changing the structure of the URL if possible, since its form is provided as a spec to a client application. is there a good way to get all the values without changing the parameter name?
You can use the default Ruby CGI module to parse the query string in a Rails controller like so:
params = CGI.parse(request.query_string)
This will give you what you want, but note that you won't get any of Rails other extensions to query string parsing, such as using HashWithIndifferentAccess, so you will have to us String rather than Symbol keys.
Also, I don't believe you can set params like that with a single line and overwrite the default rails params contents. Depending on how widespread you want this change, you may need to monkey patch or hack the internals a little bit. However the expeditious thing if you wanted a global change would be to put this in a before filter in application.rb and use a new instance var like #raw_params
I like the CGI.parse(request.query_string) solution mentioned in another answer. You could do this to merge the custom parsed query string into params:
params.merge!(CGI.parse(request.query_string).symbolize_keys)