Ruby Hash: can't convert String into Integer - ruby-on-rails

I am new to Ruby, and I am having some problems with hashes.
I have XML returned from the YouTube API that I converted into a hash. Here is the hash returned by Hash.from_xml(): http://pastebin.com/9xxE6iXU
I am trying to grab specific elements from the hash for each result, such as the title, link, author, etc. Whenever I try to loop through the hash or grab a specific element, I receive a "can't convert String into Integer" error.
Here is the code I am using for the loop:
#data["feed"]["entry"]["title"].each do |key, value|
"<p>"+key+" "+value+"</p>"
end
I have also tried grabbing specific elements, such as #data["feed"]["entry"]["title"][0].
How do I loop through the hash and grab specific elements out?

That's happening because #data["feed"]["entry"] is array of hashes:
puts #data["feed"]["entry"].class # => Array
Each element-hash inside this array has "id", "category", "title" etc. values.
For grabbing each title try to use following snippet:
#data["feed"]["entry"].each do |entry|
puts entry["title"]
end
# => "TABE test adult basic education"
"WhatCollegesHopeYouWon'tFindOutAboutACTSATTestPrep..."
....

Related

Ruby on rails array - no implicit conversion of symbol into integer

I made a table component using react js, which uses columns to display data (which works fine with other data). For example, column 1 would show the title, column 2 the year, and column 3 the format.
Here is an example of my JSON:
{"movies": [{"title": "Iron Man", "year": "2008", "format": "DVD"}, {"title": "Iron Man 2", "year": "2010", "format": "DVD"}, {"title": "Iron Man 3", "year": "2013", "format": "DVD"}]}
Here is my code to populate the table, but it does not seem to work:
#movieList = #Makes a call to my mock API to get list of movies
#movies = Array.new
#movieList.each do |item|
#movie = Hash.new
#movie[:column1] = item[:title]
#movie[:column2] = item[:year]
#movie[:column3] = item[:format]
#movies << #movie
end
I need some advice to overcome a "no implicit conversion of symbol into integer error" I get. Could anyone offer some advice and point out where I am going wrong?
tl;dr
use #movieList["movies"].each
explanation
The issue here, is that you act as though your #movieList is ann array, when it is actually a hash (assuming #movieList is the JSON you showed).
each works on both arrays and hashes. However, when you use it on a hash, the block is passed |key, val|. Also, assigning block variables is optional. So, when you say #movieList.each do |item|, item is actually the top level key of the hash ("movies").
Strings such as "movies" respond to [] indexing with numbers. That's why you get the error no implicit conversion of symbol into integer ... because you pass a symbol to String#[] and it expects an integer.
Another way to write this code, that is more idiomatic, would be like so:
#movies = #movieList["movies"].map do |movie|
{
column1: movie["title"],
column2: movie["year"],
column3: movie["format"]
}
end
try reassigning
#movieList = #movieList[:movies] this will solve your problem. You're trying to iterate a object instead of an array.
lemme know if it solves your problem.
You need to loop movies using #movieList["movies"] as your JSON is a hash that has a key 'movies' and an array of movies as a value => {'movies': [{...},{...},...]}
As #max pleaner explained assigning block variables is optional, but when you use each on a hash(your JSON in this case) and provide only one block variable (instead of two refering to the keys and values of the hash), your key-value pairs are converted to two-element arrays inside the block where first element is the key and second one is the value of the pair.
Your item looks like this inside your each block -
['movies', [{movie1}, {movie2},..]], hence:
item[0] # 'movies'
item[1] # [{movie1}, {movie2},...]
As arrays expect indexing with integers and you supply symbol (item[:title]), you receive:
TypeError (no implicit conversion of Symbol into Integer)

How to iterate through array of strings from database Ruby on Rails

I save an array of strings to my rails database, but when I go to use it in the view, I believe it is printing the string definition of the array. Am I dealing with JSON here? (aka when it saves to the database is it just an array wrapped in a string?)
How do I have it so that in my view, it simply displays the items?
<%= record.items %>
displays inside my html tag:
["item1", "item2", "item3"]
I tried iterating through record.items.each do |item| but that did not work.
If you're saving an "exact" array as a String, then Array#each won't work, because isn't a method in the String class.
Maybe isn't the best option, but you could use JSON.parse and this way get your array and be able to iterate over each object inside:
require 'json'
str = '["item1", "item2", "item3"]'
JSON.parse(str).each { |item| p item }
# "item1"
# "item2"
# "item3"
In order this work your string must be an array, in your example the second item is missing its double quote.
You could consider working with serialization or array data types depending on you current database.
A better approach to your issue is to serialize your items column. I think by default it's Array but you can use Hash or JSON.
class Record < ActiveRecord::Base
serialize :items
end
Calling record.items returns the data exactly the way you need. If you go with this you'll have to update your old records to support it.

converting ruby hash into json object

So I am iterating through a set of data and building a hash from it:
clean_response = Array.new
response.each_with_index do |h, idx|
clean_response <<
{
:lat => h["location"]["latitude"],
:lg => h["location"]["longitude"],
:place => h["location"]["name"],
#This grabs the entire hash at "location" because we are wanting all of that data
:profile_picture => h["user"]["profile_picture"],
:hash_tags => h["tags"],
:username => h["user"]["username"],
:fullname => h["user"]["full_name"],
:created_time => (Time.at(h["created_time"].to_i)).to_s,
:image => h["images"]["low_resolution"]["url"] # we can replace this with whichever resolution.
}
end
Which return an array of hashes like so:
[{:lat=>40.7486382,
:lg=>-73.9487686,
:place=>"The Cliffs at LIC",
:profile_picture=>"http://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-19/s150x150/12104940_1653775014895036_286845624_a.jpg",
:hash_tags=>["bouldering"],
:username=>"denim_climber",
:fullname=>"DenimClimber",
:created_time=>2015-10-13 22:58:09 -0400,
:image=>"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/11856571_1062082890510188_611068928_n.jpg"},
{:lat=>40.7459602,
:lg=>-73.9574966,
:place=>"SHI",
:profile_picture=>"http://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-19/11348212_1453525204954535_631200718_a.jpg",
:hash_tags=>["cousins", "suchafunmoment", "johnlennonstyle"],
:username=>"xiomirb",
:fullname=>"Xiomi",
:created_time=>2015-10-13 22:57:21 -0400,
:image=>"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/11375290_1688934151392424_2009781937_n.jpg"}]
I'd like to convert this data to json and then serve it to a specific view.
How can I convert this? I tried the .to_json method but it doesn't return a well formatted one since my UI isn't binding to the data.
You can convert a Ruby hash into JSON using to_json:
require 'json'
your_hash.to_json # gives you a JSON object
But, in your case the data is an array of hashes, but NOT a hash. So, your to_json would not work.
I am not quite sure how you want to do this, but one possibility is to loop through the array of hashes, get each hash and convert that to a JSON object using to_json call (like shown above) and build a new array of JSON objects. This way, you can build an array of JSON objects from an array of hashes.
array_of_json = []
# loop through the array of hashes
clean_response.each do |hash|
array_of_json << hash.to_json
end
array_of_json # array of JSON objects
If by "serve it to a specific view" you mean pass it to a .haml or .erb template, you can pass the array of hashes as is. Both haml and erb will allow you to iterate over the array, and even the hash if you want.
If you mean you want to hand a json string to the browser, #to_json should work fine. Other options are jbuilder or oat when you want to refine what is sent, but to_json should "serve" you well!

Rails: JSON attribute is handled as a method. No method error

I am having problems accessing the attributes of my JSON data. Instead of accessing the JSON data it thinks it is a function.
#response = HTTParty.get('http://localhost:4000/test')
#json = JSON.parse(#response.body)
#json.each do |pet|
MyModel.create(pet) ! WORKS
puts "my object #{pet}" ! WORKS
puts "my object attribute #{pet.myattribute}" ! DOES NOT WORK
end
With no MethodError myattribute.
Thank you for any help!
You may be used to JavaScript, where both object.some_key and object["some_key"] do the same thing. In Ruby, a hash is just a hash, so you have to access values via object["some_key"]. A Struct in Ruby is similar to a JavaScript object, in that you can access values both ways, but the keys have to be pre-defined.
#json = JSON.parse(#response.body) returns a hash, so you would need to do
puts "my object attributes #{pet['id']}, #{pet['title']}"
you might want to convert to HashWithIndifferentAccess so you can use symbols instead of quoted strings, i.e.
#json = JSON.parse(#response.body).with_indifferent_access
# ...
puts "my object attributes #{pet[:id]}, #{pet[:title]}"

Get value of a key in an array of hashes

I'm fairly new to ruby on rails and I'm having some trouble trying to extract a key value from an array of hashes (#sorted) when using options_from_collection_for_select in my html.haml file.
So far I've tried
options_from_collection_for_select(#sorted, "#{#sorted['id']}",
"#{#sorted['name']}")
options_from_collection_for_select(#sorted, #sorted['id'], #sorted['name'])
But both give me a "Can't convert string to integer" error I've tried calling to_i but the error still persists.
Array of Hashes (#sorted)
#sorted => [{"id"=>"51a7ba4154b3289da800000f", "name"=>"Book1", "count"=>8},
{"id"=>"519d24ed54b328e512000001", "name"=>"Book2", "count"=>5},
{"id"=>"5258917b54b32812cd000003", "name"=>"Book3", "count"=>1}]
With options_for_select:
options_for_select(#sorted.map{|hash| [hash["id"],hash["name"]]})
Remember that when you have an array, it is made up of multiple elements, and the methods you call on it are array methods, not methods for the elements inside.
In this case, each element is a hash, so your array looks like the following:
[ {"id" => 1, "name" => "Name 1"}, {"id" => 2, "name" => "Name 2" ]
The class itself is an array. You can index in to an array like so:
myArray[1]
This method takes an integer and finds the nth element. So doing:
#sorted[1]
Would return this hash element:
{"id" => 2, "name" => "Name 2"}
And now you can call hash methods on it. This is why you were getting that error, because the Array#[] method assumed you were giving it an integer to index in to the array, but you were giving it a string - a string that could not be converted in to an integer.
So in your particular case, you probably mean to do:
#sorted.first["id"], #sorted.first["name"]
(Doing #sorted.first is an alternative to #sorted[0] to get the first element in an array)

Resources