How can I use JSON data with Ruby? - ruby-on-rails

This seems really simple but I've looked all over and I can't find any documentation for this.
I have the following json file:
//data.json
{
"movie1": [
{"name": "Inception"}
]}
and I just want to print the value of name with Ruby.
json = File.read('data.json')
data = JSON.parse(json)
data['movie1']['name']
But I'm getting the error
"no implicit conversoin of String into Integer"
How can I print name?

"no implicit conversion of String into Integer" usually comes when you're trying to use an array as a hash. Array[] expects an index (integer). Your data is a hash inside an array inside a hash :
You need :
data['movie1'][0]['name']
or
data.dig('movie1', 0, 'name')

Related

string to json after getting value from redis ruby

I created a simple json object something like this:
a = {"b": 1, "c": 2}
Setting the json object as value in redis like this:
LocalCache.set('abc', a)
After getting the value from redis, I am getting a string value:
x = LocalCache.get('abc')
I want this string to be converted back to JSON object but I am unable to do it.
When I tried x.as_json, I am getting "{:b=>1, :c=>2}"
When I tried x.to_json, I am getting "\"{:b=\\u003e1, :c=\\u003e2}\""
When I tried JSON.parse(x), I am getting this error:
JSON::ParserError: 785: unexpected token at '{:b=>1, :c=>2}'
Any help would be highly appreciated.
"{:b=>1, :c=>2}"
Is not valid json. It's a ruby hash. Cast it to json before cache-ing it and then parse it after you retrieve it.
LocalCache.set('abc', a.to_json)
x = LocalCache.get('abc')
JSON.parse(x)
From Redis documentation: https://github.com/redis/redis-rb#storing-objects
Redis stores only strings as values. You have to serialize the value you are setting to as json and then parse it back as JSON after retrieving.
a = {"b": 1, "c": 2}
Here a is object of class Hash. Hence serialize while storing
x = LocalCache.set("abc", a.to_json)
To retrieve: x = JSON.parse LocalCache.get('abc')
p x # {"b"=>1, "c"=>2}

Get price from variants object with shopify_api - and ruby on rails

I'm using shopify_api (https://github.com/Shopify/shopify_api) to create an app for Shopify using Ruby.
For a Base::Product, by calling directly product.variants, i will have:
[#<ShopifyAPI: :Variant: 0x00007fa15cb0e960 #attributes={
"id"=>12664776392816,
"title"=>"Default Title",
"price"=>"5.00",
"sku"=>"",
"position"=>1,
"inventory_policy"=>"deny",
"compare_at_price"=>nil,
"fulfillment_service"=>"manual",
"inventory_management"=>nil,
"option1"=>"Default Title",
"option2"=>nil,
"option3"=>nil,
"created_at"=>"2018-08-27T03:17:24-04:00",
"updated_at"=>"2019-04-07T23:52:00-04:00",
"taxable"=>true,
"barcode"=>"",
"grams"=>0,
"image_id"=>nil,
"weight"=>0.0,
"weight_unit"=>"kg",
"inventory_item_id"=>12758757474416,
"inventory_quantity"=>0,
"old_inventory_quantity"=>0,
"requires_shipping"=>true,
"admin_graphql_api_id"=>"gid://shopify/ProductVariant/12664776392816"
}, #prefix_options={
:product_id=>1389200408688
}, #persisted=true>
]
In this case, how do I directly get price attribute from this json returned
EDIT:
I just jump in ruby on rails in the middle, so here is what I have tried so far:
product.variants.prices --> in my guts it definitely does not work, but might as well trying
returns with undefined methodprice' for #`
parse the JSON
1) JSON.parse(product.varient)['price']
returns with
no implicit conversion of Array into String
2) variant = ActiveSupport::JSON.decode(product.variants[0])
or variant = ActiveSupport::JSON.decode(product.variants)
then
variant['price']
but both return with no implicit conversion of ShopifyAPI::Variant into String
product = ShopifyAPI::Product.find(shopify_product_id)
product.variants.map(&:price)
it will give you an array of price because product might have multiple variants.
you can also use .pluck method instead of .map

parsing JSON request

The following #request = JSON.parse(request.body.read) is generating:
[
{
"application_id"=>"216",
"description"=>"Please double check date and time",
"release_date"=>"2018-12-01",
"auth"=>"someBigData"
}
]
However a blank is returned if invoking
Rails.logger.info #request['application_id']
and
if #request['auth'] == 'someBigData'
is generating a
TypeError (no implicit conversion of String into Integer):` in `app/controllers/base_controller.rb:55:in '[]'
What is wrong syntactically?
You're getting an array of hashes back, which is why #request['application_id'] returns a blank for you.
You'll need to do #request.first['application_id'] or #request[0]['application_id'] to index into your array.
As it's been already stated, you get this error cause #request is an array of hashes rather than a hash itself. To access "application_id" key of the first element you can also use dig method:
#request.dig(0, "application_id")
this way there is not going to be an exception in case #request is empty.

Generation of table and accessing elements of a Array of Hashes

I have the following Array of hashes in a rails application:
a = ["{\"ROW1\"=>{\"correct\"=>{\"h\"=>\"10\", \"m\"=>\"11\", \"l\"=>
\"12\"}, \"wrong\"=>{\"h\"=>\"2\", \"m\"=>\"2\", \"l\"=>\"4\"}, \"blank
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"3\"}}, \"ROW2\"=>{\"correct
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"4\"}, \"wrong\"=>{\"h
\"=>\"4\", \"m\"=>\"6\", \"l\"=>\"6\"}, \"blank\"=>{\"h\"=>\"7\",
\"m\"=>\"5\", \"l\"=>\"6\"}}, \"ROW3\"=>{\"correct\"=>{\"h\"=>\"4\",
\"m\"=>\"6\", \"l\"=>\"7\"}, \"wrong\"=>{\"h\"=>\"6\", \"m\"=>\"7\",
\"l\"=>\"5\"}, \"blank\"=>{\"h\"=>\"7\", \"m\"=>\"9\", \"l\"=>
\"3\"}}}"]
I want to access its elements and create a database table from it, in the following format
ROW1 correct h=10, m=11,l=12
wrong h=2, m=2,l=4
blank h=2, m=4,l=3
...and similar for ROW2 and ROW3.
How can I do that?
I tried to access a value using
a["ROW1"]["Correct"]["h"]
...but it returns a nil value.
How to access the values of this array of hashes?
you need to first convert the string to hash which can be done as follows:
require 'json'
a = ["{\"ROW1\"=>{\"correct\"=>{\"h\"=>\"10\", \"m\"=>\"11\", \"l\"=>
\"12\"}, \"wrong\"=>{\"h\"=>\"2\", \"m\"=>\"2\", \"l\"=>\"4\"}, \"blank
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"3\"}}, \"ROW2\"=>{\"correct
\"=>{\"h\"=>\"2\", \"m\"=>\"4\", \"l\"=>\"4\"}, \"wrong\"=>{\"h
\"=>\"4\", \"m\"=>\"6\", \"l\"=>\"6\"}, \"blank\"=>{\"h\"=>\"7\",
\"m\"=>\"5\", \"l\"=>\"6\"}}, \"ROW3\"=>{\"correct\"=>{\"h\"=>\"4\",
\"m\"=>\"6\", \"l\"=>\"7\"}, \"wrong\"=>{\"h\"=>\"6\", \"m\"=>\"7\",
\"l\"=>\"5\"}, \"blank\"=>{\"h\"=>\"7\", \"m\"=>\"9\", \"l\"=>
\"3\"}}}"
]
hash_string = a[0]
hash = JSON.parse hash_string.gsub("\n", '').gsub('=>', ':')
# you access the hash now:
hash["ROW1"]["correct"]["h"]
# => 10
Btw, please note that there is a typo. Instead of Correct, the key is correct with small c instead of capital C.
Hope it helps : )

Why am I getting this TypeError - "can't convert Symbol into Integer"?

I have an array of hashes. Each entry looks like this:
- !map:Hashie::Mash
name: Connor H Peters
id: "506253404"
I'm trying to create a second array, which contains just the id values.
["506253404"]
This is how I'm doing it
second_array = first_array.map { |hash| hash[:id] }
But I'm getting this error
TypeError in PagesController#home
can't convert Symbol into Integer
If I try
second_array = first_array.map { |hash| hash["id"] }
I get
TypeError in PagesController#home
can't convert String into Integer
What am I doing wrong? Thanks for reading.
You're using Hashie, which isn't the same as Hash from ruby core. Looking at the Hashie github repo, it seems that you can access hash keys as methods:
first_array.map { |hash| hash.id }
Try this out and see if that works--make sure that it doesn't return the object_id. As such, you may want to double-check by doing first_array.map { |hash| hash.name } to see if you're really accessing the right data.
Then, provided it's correct, you can use a proc to get the id (but with a bit more brevity):
first_array.map(&:id)
This sounds like inside the map block that hash is not actually a hashie - it's an array for some reason.
The result is that the [] method is actually an array accessor method and requires an integer. Eg. hash[0] would be valid, but not hash["id"].
You could try:
first_array.flatten.map{|hash| hash.id}
which would ensure that if you do have any nested arrays that nesting is removed.
Or perhaps
first_array.map{|hash| hash.id if hash.respond_to?(:id)}
But either way you may end up with unexpected behaviour.

Resources