Consume JSON - Shopify API response - ruby-on-rails

I'm trying to work with what I think is a JSON response from Shopify. It looks like this:
=> #<ActiveResource::Collection:0x007f61f45c3840
#elements=
[#<ShopifyAPI::Product:0x007f61f45c3638
#attributes=
{"id"=>2156425793,
"title"=>"Hue Women's Python Net Tight, Black, Small-Medium",
"body_html"=>"Python pattern",
"vendor"=>"HUE",
"product_type"=>"Apparel",
"created_at"=>"2015-10-02T09:42:07-04:00",
"handle"=>"hue-womens-python-net-tight-black-small-medium",
"updated_at"=>"2015-10-02T09:42:07-04:00",
"published_at"=>"2015-10-02T09:42:07-04:00",
"template_suffix"=>nil,
"published_scope"=>"global",
"tags"=>"",
"variants"=>
[#<ShopifyAPI::Variant:0x007f61f45c11a8
#attributes=
{"id"=>6989658561,
"title"=>"First",
"price"=>"18.00",
"sku"=>"123",
"position"=>1,
"grams"=>0,
"inventory_policy"=>"deny",
"compare_at_price"=>"18.00",
"fulfillment_service"=>"amazon_marketplace_web",
"inventory_management"=>"shopify",
"option1"=>"First",
"option2"=>nil,
"option3"=>nil,
"created_at"=>"2015-10-02T09:42:07-04:00",
"updated_at"=>"2015-10-02T09:42:07-04:00",
"requires_shipping"=>true,
"taxable"=>true,
"barcode"=>nil,
"inventory_quantity"=>1,
"old_inventory_quantity"=>1,
"image_id"=>nil,
"weight"=>0.0,
"weight_unit"=>"lb"},
#persisted=true,
#prefix_options={:product_id=>2156425793}>,
#<ShopifyAPI::Variant:0x007f61f45b4d18
#attributes=
{"id"=>6989658625,
"title"=>"Second",
"price"=>"18.00",
"sku"=>"345",
"position"=>2,
"grams"=>0,
"inventory_policy"=>"deny",
"compare_at_price"=>"18.00",
"fulfillment_service"=>"amazon_marketplace_web",
"inventory_management"=>"shopify",
"option1"=>"Second",
"option2"=>nil,
"option3"=>nil,
"created_at"=>"2015-10-02T09:42:07-04:00",
"updated_at"=>"2015-10-02T09:42:07-04:00",
"requires_shipping"=>true,
"taxable"=>true,
"barcode"=>nil,
"inventory_quantity"=>3,
"old_inventory_quantity"=>3,
"image_id"=>nil,
"weight"=>0.0,
"weight_unit"=>"lb"},
#persisted=true,
#prefix_options={:product_id=>2156425793}>],
"options"=>
[#<ShopifyAPI::Option:0x007f61f45a92b0
#attributes={"id"=>2550138369, "product_id"=>2156425793,
"name"=>"Title", "position"=>1, "values"=>["First", "Second"]},
#persisted=true,
#prefix_options={}>],
"images"=>
[#<ShopifyAPI::Image:0x007f61f459b390
#attributes=
{"id"=>5116928641,
"position"=>1,
"created_at"=>"2015-10-02T09:42:07-04:00",
"updated_at"=>"2015-10-02T09:42:07-04:00",
"src"=>"https://cdn.shopify.com/s/files/1/0842/7077/products
/41ooqKhDYRL._UL1500.jpeg?v=1443793327",
"variant_ids"=>[]},
#persisted=true,
#prefix_options={:product_id=>2156425793}>],
"image"=>
#<ShopifyAPI::Image:0x007f61f4598050
#attributes=
{"id"=>5116928641,
"position"=>1,
"created_at"=>"2015-10-02T09:42:07-04:00",
"updated_at"=>"2015-10-02T09:42:07-04:00",
"src"=>"https://cdn.shopify.com/s/files/1/0842/7077/products
/41ooqKhDYRL._UL1500.jpeg?v=1443793327",
"variant_ids"=>[]},
#persisted=true,
#prefix_options={:product_id=>2156425793}>},
#persisted=true,
#prefix_options={}>],
#original_params={:title=>"Hue Women's Python Net Tight"},
#resource_class=ShopifyAPI::Product>
The response I get from searching for a product via the Shopify API is of the class:
ActiveResource::Collection
I first tried turning that to JSON with .to_json but thats just a string and I can't loop thru it easily.
I then tried to turn it to an array with .to_a but now I can't get into the data..
The original response is in the x variable and now its an array.. If I try
x[0] - I get the original response back
x[1] - nil
X[0]["id] - NoMethodError: undefined method `[]' for
#<ShopifyAPI::Product:0x007f61f45c3638>
x["id"] - TypeError: no implicit conversion of String into Integer
x[0][0] - NoMethodError: undefined method `[]' for
#<ShopifyAPI::Product:0x007f61f45c3638>
x[0].class - Shopify::Product which is a ActiveResource::Collection
x[0].to_array - NoMethodError: undefined method `to_array' for
#<ShopifyAPI::Product:0x007f61f45c3638>

The data you show is an array of Product instances. Simply take the data, which I'll call data, and loop through it to get each product.
data.each do |product|
puts product.title
puts product.vendor
end
You can obviously extend your functionality from here.

Related

ArgumentError (comparison of Hash with Hash failed) - Filtering array results by matching has values

Here are samples of my arrays:
Array #1:
todays_listings_clean =
{:id=>"48442", :address=>"5489 Milburough Line", :locality=>"Burlington", :neighbourhood=>"Rural Burlington", :lot_front=>147.0, :lot_depth=>665.0, :property_type=>"Detached", :asking_price=>2888000}
{:id=>"48446", :address=>"275 St Leonard's Ave", :locality=>"Toronto", :neighbourhood=>"Lawrence Park", :lot_front=>15.0, :lot_depth=>45.0, :property_type=>"Detached", :asking_price=>3395000}
Array #2:
past_listings_clean =
{:address=>"36 Beachgrove Cres", :locality=>"Whitby", :neighbourhood=>"Taunton North", :lot_front=>3.0, :lot_depth=>9.0, :property_type=>"Detached", :closed_price=>344000, :sold_date=>#<Date: 2013-03-05 ((2456357j,0s,0n),+0s,2299161j)>}
{:address=>"4 Irene Cres", :locality=>"Brampton", :neighbourhood=>"Fletcher''s Meadow", :lot_front=>9.0, :lot_depth=>29.0, :property_type=>"Detached", :closed_price=>394900, :sold_date=>#<Date: 2013-03-04 ((2456356j,0s,0n),+0s,2299161j)>}
I am trying to run the following logic and am getting ArgumentError (comparison of Hash with Hash failed) :
todays_listings_clean.each do |tl|
past_listings_clean.select do |pl|
(pl[:locality] == tl[:locality]) &&
(pl[:neighbourhood] == tl[:neighbourhood]) &&
!(pl[:closed_price]).nil?
end
end
Any thoughts on why this issue is occurring and how to fix it?
Thanks

Why do I get "undefined method 'fetch' for nil:NilClass (NoMethodError)"

I'm parsing JSON data to save to my db.
The JSON data is like this:
{"id"=>889066,
"email"=>"new.user#email.com",
"created_at"=>"2014-10-24T18:46:13Z",
"updated_at"=>"2014-10-24T18:46:13Z",
"status"=>"Registered",
"custom_status"=>nil,
"first_name"=>New,
"last_name"=>User,
"latest_visitor"=>
{"id"=>16998604, "tracking_code"=>"cab237f6-50ec-4424-9ea9-b0110070a6cb"},
"url"=>{"id"=>2422287, "url"=>"http://www.website.com/"},
"referrer"=>{"id"=>4234808, "url"=>"https://www.google.ba/"},
"affiliate"=>nil,
"campaign"=>nil,
"search_term"=>
{"id"=>344901, "term"=>"puppies", "search_engine"=>"google"},
"tracking_code"=>"cab237f6-50ec-4424-9ea9-b0110070a6cb"}]
For example I want to get the search engine value, so I do:
json = JSON.parse(response.body)
json.each do |item|
Model.create(
search_engine: item.fetch("search_term").fetch("search_engine")
)
end
This returns the error:
in 'block in <top (required)>': undefined method 'fetch' for nil:NilClass (NoMethodError)
EDIT: Here is the output of puts item.keys:
id
email
created_at
updated_at
status
custom_status
first_name
last_name
latest_visitor
url
referrer
affiliate
campaign
search_term
tracking_code
What am I doing wrong?
What you want to do is detect when the search_term is nil and do something about it.
If you want to discard it, that's easy
json = JSON.parse(response.body)
json.each do |item|
search_term = item.fetch("search_term")
next if search_term.nil?
Model.create(
search_engine: search_term.fetch("search_engine")
)
end
If you want to provide some default search_engine value when there are no search_term:
DEFAULT_SEARCH_ENGINE = "N/A"
json = JSON.parse(response.body)
json.each do |item|
search_term = item.fetch("search_term")
if search_term.nil?
search_engine = DEFAULT_SEARCH_ENGINE
else
search_engine = search_term.fetch("search_engine")
end
Model.create(
search_engine: search_engine
)
end

Ruby/Rails Net::HTTP.post_form nested hash items html escaped

Example I am doing this in rails console:
params = {"type"=>["raka"], "fields"=>["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0", "t2", "t3", "t4"], "railing"=>["A-3"], "wood"=>["wood_6"], "railing_m"=>"0", "order"=>{"sving"=>"right", "size"=>{"ground"=>"123", "floor"=>"6", "a"=>"6", "d"=>"6"}, "comments"=>{"step_2"=>"", "step_3"=>"", "step_4"=>""}, "railing"=>{"1"=>"1", "2"=>"1"}, "railing_m"=>{"1"=>"", "2"=>"", "3"=>"", "4"=>"12"}, "hul"=>{"l"=>"123", "b"=>"123"}, "name"=>"qwed", "email"=>"mail#example.com", "phone"=>"13123", "street"=>"iuuj", "city"=>"ui", "postnr"=>"213"}}
x = Net::HTTP.post_form(URI.parse('http://localhost:3000/download.pdf'), params)
In my Rails console I can see the HTTP post request:
Started POST "/download.pdf" for 127.0.0.1 at 2013-04-15 16:25:36 +0200
Processing by PublicController#show_pdf as */*
Parameters: {"type"=>"raka", "fields"=>"t4", "railing"=>"A-3", "wood"=>"wood_6
", "railing_m"=>"0", "order"=>"{\"sving\"=>\"right\", \"size\"=>{\"ground\"=>\"1
23\", \"floor\"=>\"6\", \"a\"=>\"6\", \"d\"=>\"6\"}, \"comments\"=>{\"step_2\"=>
\"\", \"step_3\"=>\"\", \"step_4\"=>\"\"}, \"railing\"=>{\"1\"=>\"1\", \"2\"=>\"
1\"}, \"railing_m\"=>{\"1\"=>\"\", \"2\"=>\"\", \"3\"=>\"\", \"4\"=>\"12\"}, \"h
ul\"=>{\"l\"=>\"123\", \"b\"=>\"123\"}, \"name\"=>\"qwed\", \"email\"=>\"mail#example.com\", \"phone\"=>\"13123\", \"street\"=>\"iuuj\", \"city\"=>\"ui\", \"postn
r\"=>\"213\"}"}
The problem is that all the nested http params are HTML escaped. How do I get rid of that?
The .post_form method accepts strings, so it causes this escaping problem when passed a nested hash. I had this same problem and switched to the .post method, and solved it.
require "net/http"
uri = URI('http://www.yoururl.com')
http = Net::HTTP.new(uri.host)
response = http.post(uri.path, params.to_query)
Note also the use of the .to_query method of converting a hash to a string. See here
In Rails world, params is not a regular Hash object that Ruby provides out of the box. In fact its a HashWithIndifferentAccess that is provided by Rails that allows the keys to be accessed, as a symbol or as a string.
irb(main):001:0>params = {"type"=>["raka"], "fields"=>["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0", "t2", "t3", "t4"], "railing"=>["A-3"], "wood"=>["wood_6"], "railing_m"=>"0", "order"=>{"sving"=>"right", "size"=>{"ground"=>"123", "floor"=>"6", "a"=>"6", "d"=>"6"}, "comments"=>{"step_2"=>"", "step_3"=>"", "step_4"=>""}, "railing"=>{"1"=>"1", "2"=>"1"}, "railing_m"=>{"1"=>"", "2"=>"", "3"=>"", "4"=>"12"}, "hul"=>{"l"=>"123", "b"=>"123"}, "name"=>"qwed", "email"=>"mail#example.com", "phone"=>"13123", "street"=>"iuuj", "city"=>"ui", "postnr"=>"213"}}
irb(main):002:0>params.class
=> Hash
irb(main):003:0>params[:fields]
=> nil
irb(main):004:0>params = params.with_indifferent_access
irb(main):005:0>params.class
=> ActiveSupport::HashWithIndifferentAccess
irb(main):006:0>params[:fields]
=> ["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0", "t2", "t3", "t4"]

Ruby - how to get values from an array which has other arrays and hashes?

I have data in this format:
{"values"=>
[
{"updateKey"=>"UNIU-16268324-5608633092144111616-SHARE",
"updateComments"=>{"_start"=>1,
"values"=>[{"comment"=>"Sample test this is mike testing.",
"person"=>{"siteStandardProfileRequest"=>{"url"=>"http://www.linkedin.com/profile?viewProfile=&key=116654056&authToken=xVLh&authType=name&trk=api*a140290*s148640*"},
"lastName"=>"DeLorenzo",
"headline"=>"--",
"id"=>"QM86-RIKjb",
"pictureUrl"=>"http://media.linkedin.com/mpr/mprx/0_OurBLnHMma92b4U4pecXLq2MuW8aFOo4ywXHLqEbPuNO4sjZtEhUwNOWCFhAkJIq07-WoP4V_Zqg", "firstName"=>"Jennifer",
"apiStandardProfileRequest"=>{"url"=>"http://api.linkedin.com/v1/people/QM86-RIKjb", "headers"=>{"values"=>
[{"name"=>"x-li-auth-token",
"value"=>"name:xVLh"}],
"_total"=>1}}},
"timestamp"=>1337202768000,
"sequenceNumber"=>1,
"id"=>80942976},
{"comment"=>"123",
"person"=>{"siteStandardProfileRequest"=>{"url"=>"http://www.linkedin.com/profile?viewProfile=&key=70292133&authToken=wEAo&authType=name&trk=api*a140290*s148640*"}, "lastName"=>"Kartsovnyk", "headline"=>"Snr Software Developer", "id"=>"7-32mNn-Ob", "pictureUrl"=>"http://media.linkedin.com/mpr/mprx/0_xjj5WPXU6fCjCExLjUa9WA69XWNS
What I am trying to do is to loop through the updateComments and get each "id" attribute for that user.
Here is what I have so far:
if linked_in_updates.values.updateComments.is_a?(Hash)
linked_in_updates.each { |key, value|
some_value = key
}
end
I am trying to extract the hash which is the updateComments with this: linked_in_updates.values.updateComments but I get the error like this:
NoMethodError: undefined method `updateComments' for #<Array:0x13228fc20>
Any idea what I am doing wrong?
try to replace
linked_in_updates.values.updateComments.is_a?(Hash)
with
linked_in_updates.values[0]['updateComments'].is_a?(Hash)

undefined method `collect' for 2:Fixnum

def function1
#user=User.find(params[:user_id])
#participants=Participant.find_all_by_user_id(params[:user_id])
bar_1_data = #user.get_total
bar_2_data = params[:count]
color_1 = 'c53711'
color_2 = '0000ff'
min=0
max=100
puts(bar_1_data) # prints 2 on console
puts(bar_2_data) # prints 3 on console
puts (bar_1_data).is_a? Integer # prints true
puts (bar_2_data).is_a? Integer # prints false
bc=GoogleChart::BarChart.new("300x80", " ", :horizontal, false)
bc.data " ", [100], 'ffffff'
bc.data "Bar1", bar_1_data, color_1
bc.data "Bar2", bar_2_data.to_i, color_2
bc.axis :x, :range => [min,max]
bc.show_legend = true
bc.stacked = false
bc.data_encoding = :extended
#bc= bc.to_url
end
end
I am getting the argument error "comparison of String with 100 failed" int the above controller code. Then I changed the lines
bc.data "Bar1", bar_1_data, color_1
bc.data "Bar2", bar_2_data, color_2
to
bc.data "Bar1", bar_1_data.to_i, color_1
bc.data "Bar2", bar_2_data.to_i, color_2
which gives me undefined method collect for 2:Fixnum at line #bc= bc.to_url.
On console it gives the following error:
NoMethodError (undefined method `collect' for 2:Fixnum):
gchartrb (0.8) lib/google_chart/base.rb:499:in `extended_encode'
gchartrb (0.8) lib/google_chart/base.rb:461:in `encode_data'
gchartrb (0.8) lib/google_chart/bar_chart.rb:69:in `process_data'
gchartrb (0.8) lib/google_chart/bar_chart.rb:68:in `collect'
gchartrb (0.8) lib/google_chart/bar_chart.rb:68:in `process_data'
gchartrb (0.8) lib/google_chart/base.rb:440:in `add_data'
gchartrb (0.8) lib/google_chart/base.rb:305:in `prepare_params'
gchartrb (0.8) lib/google_chart/base.rb:77:in `to_url'
app/controllers/assess_controller.rb:139:in `function1'
gchartrb (0.8) lib/google_chart/bar_chart.rb:22:in `initialize'
app/controllers/assess_controller.rb:131:in `new'
app/controllers/assess_controller.rb:131:in `function1'
/Library/Ruby/Gems/1.8/gems/hoptoad_notifier-2.4.11/lib/hoptoad_notifier/rack.rb:27:in `call'
/Library/Ruby/Gems/1.8/gems/hoptoad_notifier-2.4.11/lib/hoptoad_notifier/user_informer.rb:12:in `call'
Rendering rescues/layout (internal_server_error)
Tried printing bc in the view as <p><img src="<%= puts (#bc) %>" ></p>,it doesn't print anything, but when I am printing bc in the controller it prints
#<GoogleChart::BarChart:0x103be9660>.
Am I not sending it correctly to the view? I have tried both #bc=bc.to_url and puts bc.to_url as in http://gchartrb.rubyforge.org/.
What am I missing?
Without knowing the api for google charts, I see this:
bc.data " ", [100], 'ffffff'
bc.data "Bar1", bar_1_data, color_1
bc.data "Bar2", bar_2_data.to_i, color_2
The parameters of the first line are of type String, Array, String.
The parameters of the next two are String, Fixnum, String
Your error message is undefined method collect for 2:Fixnum ... so perhaps you should change the Fixnum to Array.
bc.data " ", [100], 'ffffff'
bc.data "Bar1", [bar_1_data], color_1
bc.data "Bar2", [bar_2_data.to_i], color_2
It looks like you're loading bar_1_data and bar_2_data into arrays. Thus the error undefined method to_i for Array.
Instead of:
bar_1_data = [#user.get_total]
bar_2_data = [params[:count]]
Just try
bar_1_data = #user.get_total
bar_2_data = params[:count]
Note that putting your data inside [] brackets means it's now an array of one item.

Resources