JSON to Ruby on Rails Create Action - ruby-on-rails

I am using an API for movies, for the most part I use a gem, but in order to get certain information, I have to use RestClient.get methods.
response = RestClient.get "http://api.themoviedb.org/3/movie/8699/keywords", headers
puts response
If I run this code, it returns this JSON "extract"
{"id":8699,"keywords":[{"id":917,"name":"journalism"},{"id":4411,"name":"sexism"},{"id":6198,"name":"ladder"},{"id":8531,"name":"panda"},{"id":18290,"name":"1970s"},{"id":18298,"name":"tv show in film"},{"id":41390,"name":"mustache"},{"id":165288,"name":"misogynist"},{"id":167241,"name":"newsroom"},{"id":167250,"name":"teleprompter"},{"id":167252,"name":"what happened to epilogue"},{"id":167254,"name":"gang warfare"},{"id":167256,"name":"multiple cameos"},{"id":179430,"name":"aftercreditsstinger"},{"id":179431,"name":"duringcreditsstinger"},{"id":185281,"name":"news spoof"}]}
Now what I need to do is be able to do is turn the above into a rails readable piece of code, so that I can then put it into a database.
More specifically, I would like to take the above information and be able to execute it as such
keywords.each do |keyword|
Keyword.create(name: keyword.name, tmdbid: keyword.id)
end
So that it creates a new Keyword based on each keyword and its name & id based on the JSON File

You can use JSON.parse to turn it into a hash
keywords = JSON.parse(response)["keywords"]

It will be faster if you create all keywords at once by first create correct array of values to be saved. Here is what I will do
keywords = JSON.parse(response)["keywords"].map do |k|
{ name: k["name"], tmdbid: k["id"] }
end
Keyword.create(keywords) #one SQL statement only
Regards

Related

Storing/Retrieving values in a Rails cookie and in different controller [duplicate]

I am trying to store an array on rails an getting error on the decoding.
I use cookies[:test] = Array.new
And when I am trying to decode
#test = ActiveSupport::JSON.decode(cookies[:test])
I am getting an error.
Whats the proper way to achieve what I am trying to ?
When writing to the cookie I usually convert the array to a string.
def save_options(options)
cookies[:options] = (options.class == Array) ? options.join(',') : ''
end
Then I convert back into an array when reading the cookie.
def options_array
cookies[:options] ? cookies[:options].split(",") : []
end
I'm not sure if this is "the right way" but it works well for me.
The "Rails way" is to use JSON.generate(array), since it's what is used in the second example in the Cookies docs:
# Cookie values are String based. Other data types need to be serialized.
cookies[:lat_lon] = JSON.generate([47.68, -122.37])
Source: http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
When you want to read it back, just use JSON.parse cookies[:lat_lon] for example, and it'll provide you an array.
Use session, not cookies. You don't have to decode it, rails handles that for you. Create the session the same way you already are:
session[:test] = Array.new
and when you need it, access it like normal
session[:test]
# => []

How to rename a symbol in hash parameters?

I have parameters from an external API that formats JSON responses using CamelCase that I want to fit into my Rails app:
{"AccountID"=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
"ChannelProductDescription"=>"0004", "Currency"=>"CAD",
"CurrentBalance"=> {"Amount"=>"162563.64", "Currency"=>"CAD"}}
Using the below script I converted them to lower case:
data = JSON.parse(response, symbolize_keys: true)
data = {:_json => data} unless data.is_a?(Hash)
data.deep_transform_keys!(&:underscore)
data.deep_symbolize_keys!
Leaving me correctly formatted params like this:
{:account_id=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
:channel_product_description=>"SAVINGS", :currency=>"CAD",
:current_balance=> {:amount=>"43.00", :currency=>"CAD"}}
I'm trying to map this external API response into a generic Rails model Account, where JSON from this API call will return cleanly as parameters into my database to allow a clean saving interface such as:
#account = Account.create(ParamParser.call(params))
But I ran into a problem with converting :account_id, as that param conflicts with the primary key of my database.
To get around this, my idea is to convert all symbol instances of params[:account_id] into params[:account_key_id], so that those params don't conflict with my databases existing account_id field.
How do I do this, and is there a better approach for consuming external JSON API's than what I've described here?
Hash#deep_transform_keys does this:
Returns a new hash with all keys converted by the block operation.
This includes the keys from the root hash and from all
nested hashes and arrays.
So you could do it in one pass with an appropriate block, something like:
data.deep_transform_keys! do |key|
key = key.underscore.to_sym
key = :account_key_id if(key == :account_id)
key
end
You might as well drop the symbolize_keys: true flag to JSON.parse too, you're changing all the keys anyway so don't bother.
If you're doing this sort of thing a lot then you could write a method that takes a key mapping Hash and gives you a lambda for transforming the keys:
def key_mangler(key_map = { })
->(key) do
key = key.underscore.to_sym
key = key_map[key] if(key_map.has_key?(key))
key
end
end
and then say things like:
data.deep_transform_keys!(&key_mangler(:account_id => :account_key_id))
You might want to use a different name than key_mangler of course but that name is good enough to illustrate the idea.
BTW, if you're sending this JSON into the database then you probably don't need to bother with symbol keys, JSON only uses strings for keys so you'll be converting strings to symbols only for them to be converted back to strings. Of course, if you're symbolizing the keys when pulling the JSON out of the database then you'll probably want to be consistent and use symbols across the board.
In addition to the previous answer...
Unfortunately, there is, to my knowledge, no method on Hash that does this in one operation. I've always accomplished this by brute force, as in:
hash[:new_key] = hash[:old_key]
hash.delete(:old_key)
A shortcut for this, suggested in the comment below by "mu is too short", is:
hash[:new_key] = hash.delete(:old_key)
To illustrate in irb:
2.4.1 :002 > h = { foo: :bar }
=> {:foo=>:bar}
2.4.1 :003 > h[:foo_new] = h.delete(:foo)
=> :bar
2.4.1 :004 > h
=> {:foo_new=>:bar}

ActiveRecord Connection Adapter return value

I had a bit more complex sql-query which i decided to use plain sql rather than writing it with AR. I wrapped the sql-statement inside ActiveRecord::Base.connection.exec_query` .
The method basically looks like that:
def sc_agent
return ActiveRecord::Base.connection.exec_query("SQL").as_json
end
The serializer as_json gives me a json hash with json strings. So also id's are now strings
{"id":"123","age":"99"}
On standard queries where i use AR i receive nicely
formatted json with the correct types.
How can i retain the correct types of all the values when using the ConnectionAdapter directly? Thanks for everything!
Use find_by_sql method.
Example: Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date].
More info is here: http://api.rubyonrails.org/classes/ActiveRecord/Querying.html

How to handle a JSON with same value names in ruby on rails

I have this JSON from spotify API:
link
I need to find a way to get the track id, preferably all the ids, but I can't find a way to assign the IDs to variables. I can only get the first one. I have been working on this problem the last 2 days and it's getting too frustrating to find the solution without asking for help.
First, read some Ruby related books.
Second, here is an example solution since you've been stuck for 2 days. You have to be rewarded for your persistence! :)
# Assume you have that result in text format in `result` variable
# It means that we need to parse it and turn it into ruby hash
result =<<RESULT
"tracks" : {
"href" : "https://api.spotify.com/v1/search?query=don%27t+worry+be+happy&offset=0&limit=1&type=track","
...
RESULT
# Let's parse it using JSON gem
require 'json'
json = JSON.parse(result)
### If your result is already parsed into Ruby hash, then skip the above code.
unless json.dig('tracks', 'items').empty?
json['tracks']['items'].map {|i| i['id'] }
end
# This will return an array of all track id's
=> ["4v52HuhZqVV0eNpP6vzH5I"]

How to store array on a cookie rails 4?

I am trying to store an array on rails an getting error on the decoding.
I use cookies[:test] = Array.new
And when I am trying to decode
#test = ActiveSupport::JSON.decode(cookies[:test])
I am getting an error.
Whats the proper way to achieve what I am trying to ?
When writing to the cookie I usually convert the array to a string.
def save_options(options)
cookies[:options] = (options.class == Array) ? options.join(',') : ''
end
Then I convert back into an array when reading the cookie.
def options_array
cookies[:options] ? cookies[:options].split(",") : []
end
I'm not sure if this is "the right way" but it works well for me.
The "Rails way" is to use JSON.generate(array), since it's what is used in the second example in the Cookies docs:
# Cookie values are String based. Other data types need to be serialized.
cookies[:lat_lon] = JSON.generate([47.68, -122.37])
Source: http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
When you want to read it back, just use JSON.parse cookies[:lat_lon] for example, and it'll provide you an array.
Use session, not cookies. You don't have to decode it, rails handles that for you. Create the session the same way you already are:
session[:test] = Array.new
and when you need it, access it like normal
session[:test]
# => []

Resources