Rails serialize not storing correctly - ruby-on-rails

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.

Related

Rails JSON store value gets quoted upon saving

I have this problem with my Rails (5.1.6) application that is running on a PostgreSQL instance.
I have a model with a JSON type column (t.json :meta). The model has a store accessor like
store :meta, accessors: [:title], coder: JSON
The problem is now when I set this value that it shows up in the database as
"{\"title\":\"I am a title\"}"
making it text rather than a JSON value, which in turn makes that I cannot use the JSON query operator (->>) to query my JSON fields. I already tried without the coder option, but this results in it being saved as YAML.
The serialize function also did not change anything for me (adding serialize :meta, JSON)
Any and all help is appreciated!
serialize and store are not intended to be used for native JSON columns. Their purpose is to marshal and un-marshal data into string columns.
This was a "poor mans" JSON storage before native JSON support existed (and was supported by ActiceRecord). Using it on a JSON column will result in a double encoded string as you have noticed.
You don't actually have to do anything to use a JSON column. Its handled by the adapter.
See:
http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
http://guides.rubyonrails.org/active_record_postgresql.html#json-and-jsonb

Ruby On Rails: Convert PostgreSQL JSON to usual JSON

I have a JSON field in my PostgreSQL database. If I do #profile.json, then I will get something like:
{ {"name"=>"jhon", "degree"=>"12312"}, "1480103144467"=>{"name"=>"", "degree"=>""}}`
It has all the => and other symbols, which I can not parse. How can I convert to normal format?
If you've declared your column of type json that's a signal to Rails to automatically serialize and decode your column on-demand, transparently. What you're seeing here is a traditional Ruby Hash structure, which is to be expected.
Inside the database itself it's stored as JSON.
If you need to re-emit this as JSON for whatever reason, like for an API, try this:
#profile.json.to_json
Calling your column something other than json is probably advisable, too.

Saving data from a JSON response

I currently have a JSON response, fairly simple one. But I couldn't find a good guide or kicking off point for getting the JSON response and saving it within a model that I have e.g posts.
"Grab a JSON feed containing posts and save each one within the posts
table in rails"
Is there a simple way to do this with rails?
Any help is greatly appreciated.
Not a lot to work with...but let's assume the json string is represented by the variable json_str.
parsed = JSON.parse(json_str)
The parsed string should now essentially just be key value pairs like any other hash. To get the value, simply use the key.
parsed["some_key"]
Will return the value. To make your post from this, you can take the values you need and pass them in one by one, like so:
Post.create(some_value: parsed["some_key"], # etc)
Or, if all of your keys happen to share names with your attributes, you can pass the params all at once by saying:
post = Post.new(parsed)
and then calling:
post.save
Let me know if you have trouble.

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.

Serialize/De-serialize objects via HTTP, Ruby (no ROR)

There is already similar question to this but I am not satisfied with answers since I am trying to do something more complex.
I have web service which provides list/single objects. Objects are Users, Categories, etc. Here is example of object:
<UserObject name="foo" description="bar" category=<Category name="cat1" description="bar"> locations=[<Location id=1>, <Location id=2>] >
In other words objects are somewhat complex and can be arrays of those objects. I am looking for a way to:
Serialize these object to JSON or Hash string
Send them over HTTP
Deserialize them to OpenStruct objects
Service that is serializing objects is not ROR.
App that is receiving and deserializing objects is ROR.
There must be some generic way to do this, I tried using to_json and JSON.parse but it only de-serializes object to one level. So for example above I would get:
<OpenStruct name="foo" description="bar" category="{\"name\"... JSON STRING}" locations="JSON STRING">
Instead of JSON STRINGs I would like to get objects inside object as it was in original.
Ruby: 1.9.3
Thanks
Take a look at the oj gem. It allows you to serialize and deserialize ruby objects to and from json. It also has the benefit of being very fast.
After looking into oj gem and contacting it's creator Peter Ohler, who was very nice and helped, I was able to get desired effect.
require 'oj'
# user instance is nested instance
json_string = Oj.dump user
# send over http
# de-serialize without domain classes (classes created by Oj gem)
user = Oj.load(json_string, { :auto_define => true })
Thanks to #josh-voigts for letting me know about the gem.

Resources