JSON date string parse error in Rails - ruby-on-rails

I've got a large data model in a Rails application that I'm trying to make serializable and output to JSON. I defined the #serializable_hash method on the model and blacklisted a few attributes. My goal is to whitelist attributes on the controller layer to accept back that same structure and simply ignore values that I don't want "accessible".
One such attribute is giving me trouble when I PUT update with the aforementioned JSON. I get an error while parsing request parameters:
SyntaxError (/Users/brad/.rvm/gems/ruby-1.9.3-p194#project-rails32/gems/actionpack-3.2.13/lib/action_dispatch/http/request.rb:261: syntax error, unexpected tINTEGER, expecting $end
...02933", "software_date"=>"09/05/14", "software_version"=>"10...
... ^):
# stack trace...
As far as Rails is concerned, this is just a string right? Why is it expecting an end of input here? For the record, taking this attribute out before submitting my request results in a successful update, so I'm sure this is what's causing the issue.

Turns out I'm the unluckiest guy in the world.
Familiarize yourself with Ruby's %Q() method, and you'll understand where I'm at.
Under my very very specific case, when Rails is parsing params for a request:
in JSON format
which has a key mapping to an Array
and any value under that Array contains a '/'
the parse will fail. Why?
My version of Rails (3.2.13) uses the AwesomePrint library version 0.3.2 when parsing out parameters for the params hash. The #grep method for that version of the gem evaluates matches using:
%Q/#{match}/
Simply because the specified delimiter is a '/', the evaluation fails and parsing crashes. DO NOT LET THIS HAPPEN TO YOU.

Related

Ruby on Rails: Trying to make multiple API requests based on an array of values. How can I insert these values as parameters into the API URL?

I'm using rest-client (2.1.0-x64-mingw32) with Ruby on Rails (v6.0.3.2).
I'm trying to make multiple API requests based on an array of values.
For example, here is a short array containing the values to be inserted in the API URL as parameters:
array = ["DUBLIN%20CITY%20COUNCIL", "SOUTH%20DUBLIN%20COUNTY%20COUNCIL"]
I will then use a loop to insert these into each request resulting in the following:
https://api.valoff.ie/api/Property/GetProperties?Fields=*&LocalAuthority=DUBLIN%20CITY%20COUNCIL&CategorySelected=OFFICE&Format=json&Download=false
https://api.valoff.ie/api/Property/GetProperties?Fields=*&LocalAuthority=SOUTH%20DUBLIN%20COUNTY%20COUNCIL&CategorySelected=OFFICE&Format=json&Download=false
First, to try inserting a single value, I have tried this:
require 'rest-client'
require 'json'
localAuthority = "DUBLIN%20CITY%20COUNCIL"
response = RestClient.get('https://api.valoff.ie/api/Property/GetProperties?Fields=*&LocalAuthority=#{localAuthority}&CategorySelected=OFFICE&Format=json&Download=false')
json = JSON.parse(response)
However, this is resulting in the following error:
rails aborted!
URI::InvalidURIError: bad URI(is not URI?): "https://api.valoff.ie/api/Property/GetProperties?Fields=*&LocalAuthority=\#{localAuthority}&CategorySelected=FUEL/DEPOT&Format=json&Download=false"
The value doesn't seem to be passing correctly into the URL. How can I insert these values as parameters into the API URL?
Take a closer look at the error. The URL in the error message contains the string
...#{localAuthority}...
The interpolation didn't work because ruby only supports #{} syntax within double quoted strings.
Try and replace your single quotes with double quotes (")
"...#{localAuthority}..."
I'll spare you the lecture on sanitizing inputs but, please, pay attention to where you get these strings from and make sure to properly escape them.

find_by() in json data

I am using ahoy gem for analytics. In the ahoy_events table, I have properties column of json data type. I want to find specific data based on that column.
Suppose I have
{"tag":"a","class":"bigyapan-6","page":"/client/dashboard","text":"","href":"http://www.google.com"}
this as data and I want to find_by class.
In the rails c I ran Ahoy::Event.find_by(properties[:class]: "bigyapan-6") and it gave me an err
Ahoy::Event.find_by(properties["class"]: "bigyapan-6")
SyntaxError: unexpected ')', expecting end-of-input
This is a syntax error since properties[:class] is not a valid hash key in Ruby. To query Postgres JSON columns you need to provide the query as a string:
Ahoy::Event.find_by("properties ->> 'class' = 'bigyapan-6'")
ActiveRecord does not take a nested hash in this case like it would for an association. I doubt that ActiveRecord will ever support this since its very RBDMS specific and the type coercion thing (-> vs ->>) would make it really complex.
# this won't work.
Ahoy::Event.find_by(properties: { class: 'bigyapan-6' })
See:
http://edgeguides.rubyonrails.org/active_record_postgresql.html#json
http://robertbeene.com/rails-4-2-and-postgresql-9-4/
Try the following:
Ahoy::Event.find_by properties["class"].to_sym 'bigyapan-6'
I think it is getting confused with string followed by :

Saving Mutiple arrays with strong parameters Ruby on Rails 4

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.

Rails serialize not storing correctly

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.

Rails JSON conversion error

I'm getting a strange error when trying to convert my object to json for an API connection. The following details my experience.
If I call
JSON.generate(self)
the output is
{"validation_context":null,"errors":{},"params":{"number":"123","name":"test"}}
I only need the params in my json object and when I call
JSON.generate(self.params) # or the next line
JSON.generate(#params) #params has been set on the object as an accessor
I get
undefined method `merge' for #<JSON::Ext::Generator::State:0x1043f1a38>
For some reason params is not considered a Hash. It serializes ok when I'm getting the parent object but fails otherwise. How can I serialize just the params?
Turns out I found a relatively simple solution.
Rather than
JSON.generate(object_to_serialize)
Using
object_to_serialize.to_json
Will work as intended.

Resources