Iterate to every element of the multidimension array in ruby - ruby-on-rails

I have a array i getting through an xml .i want to iterate every element to the array which is hash and get the every hash element value using key.
I want to someting like this>>
array>>
education_split = [{"University"=>"Institute Of Engineering And Emerging Technologies", "Degree"=>"MBA", "Year"=>"2007"}, {"University"=>"H.N.B. Garhwal University", "Degree"=>"MSC", "Year"=>"2005"}, {"University"=>"H.P. University", "Degree"=>"Med", "Year"=>"2003"}, {"University"=>nil, "Degree"=>"12th", "Year"=>"1999"}, {"University"=>nil, "Degree"=>"10th", "Year"=>nil}]
now i want to iterate to every element of the array and get the value of university ,degree,year in iteration. something like that..
education_split.each do |edu|
//here are some other things also like creating object
edu["University"]
edu ["Degree"]
edu["Year"]
end
This is also working but in some cases it is though error >> TypeError (no implicit conversion of String into Integer)
here all fields are string and values i am getting are also string.

Just need to check a hash :
education_split.each do |edu|
//here are some other things also like creating object
if edu.is_a? Hash
edu["University"]
edu ["Degree"]
edu["Year"]
end
end
Reading the error, I am sure your collection education_split contains also arrays with hashes. Now to prevent the error and as you interested only to hash that part of the code, just do a check if edu in any particular iteration, is a hash or not. if hash, do your operation or skip it.
TypeError (no implicit conversion of String into Integer) only comes, when you would try to get array elements using strings, instead of integers. Like a = [1, 2], and now do a['x'], and see you would get the exact error you are now getting.

Related

Rails, how to loop either array of hashes or only a hash

I am connecting to an API and I get array of hashes or only 1 hash for the data. So when the data comes as array of hashes;
"extras"=>{"extra"=>[{"id"=>"529216700000100800", "name"=>"Transfer Trogir - Dubrovnik (8 persons max)", "price"=>"290.0", "currency"=>"EUR", "timeunit"=>"0", "customquantity"=>"0", "validdatefrom"=>"1970-01-01", "validdateto"=>"2119-07-20", "sailingdatefrom"=>"1970-01-01", "sailingdateto"=>"2119-07-20", "obligatory"=>"0", "perperson"=>"0", "includedinbaseprice"=>"0", "payableoninvoice"=>"1", "availableinbase"=>"-1", "includesdepositwaiver"=>"0", "includedoptions"=>""}, {"id"=>"528978430000100800", "name"=>"Gennaker + extra deposit (HR)", "price"=>"150.0", "currency"=>"EUR", "timeunit"=>"604800000", "customquantity"=>"0", "validdatefrom"=>"1970-01-01", "validdateto"=>"2119-07-19", "sailingdatefrom"=>"1970-01-01", "sailingdateto"=>"2119-07-19", "obligatory"=>"0", "perperson"=>"0", "includedinbaseprice"=>"0", "payableoninvoice"=>"1", "availableinbase"=>"-1", "includesdepositwaiver"=>"0", "includedoptions"=>""}]
I'am looping through the array to get the values as;
b["extras"]["extra"].each do |extra|
puts extra["id"]
puts extra["name"]
end
But when this is not array; only 1 hash, then this is not working, adding each loop makes it array but not array of hashes;
"extras"=>{"extra"=>{"id"=>"640079840000100800", "name"=>"Comfort package (GRE)", "price"=>"235.0", "currency"=>"EUR", "timeunit"=>"0", "customquantity"=>"0", "validdatefrom"=>"1970-01-01", "validdateto"=>"2120-03-25", "sailingdatefrom"=>"2015-01-01", "sailingdateto"=>"2120-03-25", "obligatory"=>"1", "perperson"=>"0", "includedinbaseprice"=>"0", "payableoninvoice"=>"1", "availableinbase"=>"-1", "includesdepositwaiver"=>"0", "includedoptions"=>""}}
b["extras"]["extra"].each do |extra|
puts extra["id"]
puts extra["name"]
end
This time, that gives error TypeError (no implicit conversion of String into Integer);
When I type puts extra.inspect; I get ["id", "640079840000100800"]. So to make it work I should pass extra[1] to get the id number.
But I can not predict either array of hashes or only hash. Is there any easy way to solve this issue that works either array of hashes or just a hash?
Naïve solution: one might check the object’s type upfront:
case b["extras"]["extra"]
when Array
# handle array
when Hash
# handle hash
end
Proper solution: produce an array of hashes no matter what came.
[*[input]].flatten
and deal with it as with an array having at least one hash element (with each.)
Please also refer to valuable comment by #Stefan below if you have no allergy using Rails helpers.
You could try to use Object#kind_of? to determine whether it is an Array or a Hash instance.
if b["extras"]["extra"].kind_of? Array
# handle array
elsif b["extras"]["extra"].kind_of? Hash
# handle hash
end

Cannot access specific value of a hash - Rails

Hello i have been trying to access the token value of the following hash with no avail
email.to[{:token=>"example", :host=>"HOSTNAME here", :email=>"example email", :full=>"example#email.com", :name=>nil}]
does it not email.to[:token] give me the value of token?
when i do that i get this
TypeError (no implicit conversion of Symbol into Integer):
if not what is the correct way to do it. Is there any point in doing a loop when i just need one value?
email.to method returns an Array that contains a Hash
[{:a=>"a", :b=>"b"}]
so you have to specify the index of an element in that array first
email.to[0][:a]
or
email.to.first[:a]
In order to access the Hash without an index, email.to method would have to return a Hash and not an Array type. So it would have to be something likes this
def to
{:a=>"a", :b=>"b"}
end

How do you access an object's (ActiveRecord::Relation) value by key in Ruby on Rails?

tl;dr How do I get the corresponding value with the key of an object?
I'm confused why
Atag.where(tag:'brand') gives me what I would call an object for lack of a better term: #<ActiveRecord::Relation [#<Atag id: 1, tag: "brand", created_at: "2015-01-31 04:29:20", updated_at: "2015-01-31 04:29:20">]>
But I'm having the basic difficult of accessing the corresponding value for the key :id.
Atag.where(tag:'brand').id and Atag.where(tag:'brand')[:id] and Atag.where(tag:'brand')(:id) all throw errors, while in this case I'm just trying to have the integer 1 returned.
I seem to be unable to ruby, nor find a succinct answer to this basic question with my google searching skills (or lack there of).
Thanks
From great documentation at the Odin Project.
The key thing to note is that #find returns the actual record while #where returns an ActiveRecord::Relation which basically acts like an array.
So if you're using #where to find a single record, you still need to remember to go into that "array" and grab the first record, e.g. User.where(:email => "foo#bar.com")[0] or User.where(:email => "foo#bar.com").first.
This gets me all the time...
Get the id of your tag = 'brand' with following query:
Atag.find_by(tag:'brand').id
Check following variations:
Atag.find(1)
#gives you the object with the Atag id = 1
Atag.find(100) #let's say this record does not exist then you will
get ActiveRecord::RecordNotFound exception.
Better option :
Atag.where(id: 1)
#this returns you a relation and it's true you are trying to access
only a single object.
Hence, you just need to modify it to :
Atag.where(id: 1).first
#Above one will give you an object of Atag not an association result.
# to verfiy you can execute, Atag.where(id: 1).first.class
Atag.where(id: 999).first
# In this case if there is no record found with id = 999, then it'll
return nil which can be easily handled than an exception found
while using find method.
Get the same flavor using the dynamic finders.
Atag.find_by(id: 1) #gives the Atag with id 1
Atag.find_by_id(1). # same as above.
Atag.find_by(id: 999) #if not found then simply returns nil.
Atag.find_by(name: 'ruby') #return Atag object with name: 'ruby'
Atag.find_by_name('ruby') #same as above.
Yep, looks like you figured it out. For reference, you can use Atag.where(tag:'brand').first to get the first result, and Atag.where(tag:'brand').to_a to get an array of all the matching results.
where return instance of ActiveRecord::Relation which can be treated like an array with records as its members. Even if the result is single it should be accessed like a member of array with single element
Atag.where(tag: 'brand')
returns the array of results and to access id we should get the record from the array first i.e.
Atag.where(tag: 'brand')[0].id
In order to get id of all the matching records we need to use pluck with where. pluck returns an array of attribute that is plucked.
Atag.where(tag: 'brand').pluck(:id)
This would return an array of id from the collection returned by where only.
The find_by method finds the first record matching some conditions. Since find_by returns the record (not an array) , we can do:
Atag.find_by(tag: 'brand').id
PS: No one had mentioned pluck that's why I wrote this answer. Hope its helpful.

Ruby getting deeply nested JSON API data

I have a rails app which gets a response from World Weather Online API. I'm using the rest-client gem and the response is in JSON format.
I parse the response using:
parsed_response = JSON.parse(response)
Where parsed_response is obviously a hash.
The data I need are strings inside a hash inside an array inside a hash inside another array inside another hash inside another hash.
The inner-most nested hashes are inside ["hourly"], an array of 8 hashes, each with 20 keys, possessing string values of various weather parameters. Each of these hashes in the array is a different time of day (the forecast is three-hourly, 3*8 = 24hours).
So, for example, if I want the swell height in metres at 9pm, I find it with the following call:
#swell_height = parsed_data["data"]["weather"][0]["hourly"][7]["swellHeight_m"]
Where the 7th element in the array correspond to "time" => "2100"
While I can definitely work with this, I'm curious as to whether there is a more straightforward method of accessing my data, like if it was a database table, I could use active record, something like:
#swell_height = parsed_data.swellHeight_m.where(:time => "2100")
You may want to look at JSONPath. It does exactly what you need. Its syntax is very similar to XPath, but JSONPath works with JSON data (as obvious).
There is a Ruby implementation: https://github.com/joshbuddy/jsonpath
I personally use it in every project where I need to test JSON responses.

Unable to read values from object returned from ActiveRecord.find

I make the following call to the DB.
#patientRegistration = PatientRegistration.find(:all,
:conditions=>["name = '#{patientName}'"])
This searches for a patient registration based on a given name. I get a valid #patientRegistration object. When I invoke #patientRegistration.inspect it prints correctly all the values for the object in the DB.
But when I try to read a particular attribute (say id or name) by doing the following: #patientRegistration.id or #patientRegistration.name, I get invalid values. Either its blank or some junk values. I don't understand how inspect is able to retrieve all the values correctly but reading individual attributes gives invalid values.
Thanks
find(:all) returns an array of all the records that match the conditions (inspect probably shows you the result in square brackets). #patientRegistration.first.name will return you the name of the first record in the array. However, if you are only interested in the first or only record that matches the conditions, then you can use find(:first) instead:
#patientRegistration = PatientRegistration.find(:first,
:conditions => ["name = ?", patientName])
Note that I've also changed your condition to use a parameter so that it is no longer at risk from SQL injection attacks.
You can also re-write this code using an attribute-based finder:
#patientRegistration = PatientRegistration.find_by_name(patientName)
This will do a find(:first). For the equivalent of find(:all), use find_all_by instead of find_by.

Resources