Looping through Hash(Array) - ruby-on-rails

I have this problem, where I keep on getting
TypeError: can't convert String into Integer
This is where I'm going through this #data object.
here is the #data object
#data = HTTParty.get("")
{
"body"=>{
"predictions"=>{
"direction"=>{
"prediction"=>[
{
"epochTime"=>"1362931090892",
},
{
"epochTime"=>"1362931747892",
},
{
"epochTime"=>"1362932467892",
},
{
"epochTime"=>"1362933187892",
},
{
"epochTime"=>"1362933847892",
}
],
"title"=>"xxxx"
},
"a"=>"xx",
"b"=>"x"
},
"name"=>"some"
}
}
and my code to go through above has been
<% if #data["body"]["predictions"].present? %>
<% #data["body"]["predictions"].each do |p| %>
<%p["direction"].each do |d|%>
<% d["prediction"].each do |k|%>
<h4><%= k["epchoTime.."] %> </h4>
<%end%>
<%end%>
<%end%>
<%end%>
I have no idea how to go through this, I assume this is due to the fact I should access stuff like I do in C++ with name[integer] value, but I would like to use ["name"]. How can I make my code work ?
Thanks for your precious time and consideration.

Here's an example, using Nokogiri, of parsing the raw XML:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<body>
<predictions>
<direction>
<prediction>
<epochTime>1362931090892</epochTime>
<epochTime>1362931747892</epochTime>
<epochTime>1362932467892</epochTime>
<epochTime>1362933187892</epochTime>
<epochTime>1362933847892</epochTime>
</prediction>
<title">xxxx</title>
<a>"xx"</a>
<b>"x"</b>
<name>"some"</name>
</direction>
</predictions>
</body>
EOT
epoch_times = doc.search('epochTime').map(&:text)
Which returns an array of epochTime values:
[
[0] "1362931090892",
[1] "1362931747892",
[2] "1362932467892",
[3] "1362933187892",
[4] "1362933847892"
]
Sometimes we need to loop through all prediction blocks containing the epochTime blocks. This will do it:
epoch_times = doc.search('prediction').map{ |predict|
predict.search('epochTime').map(&:text)
}
[
[0] [
[0] "1362931090892",
[1] "1362931747892",
[2] "1362932467892",
[3] "1362933187892",
[4] "1362933847892"
]
]
Sometimes you need to find a particular node and grab all the elements of a certain type inside it:
doc = Nokogiri::XML(<<EOT)
<body>
<predictions>
<direction>
<prediction id="1">
<epochTime>1362931090892</epochTime>
<epochTime>1362931747892</epochTime>
<epochTime>1362932467892</epochTime>
<epochTime>1362933187892</epochTime>
<epochTime>1362933847892</epochTime>
</prediction>
<title">xxxx</title>
<a>"xx"</a>
<b>"x"</b>
<name>"some"</name>
</direction>
</predictions>
</body>
EOT
epoch_times = doc.search('prediction[id="1"]').map{ |predict| predict.search('epochTime').map(&:text) }
[
[0] [
[0] "1362931090892",
[1] "1362931747892",
[2] "1362932467892",
[3] "1362933187892",
[4] "1362933847892"
]
]

the Tin Man has a good point about keeping this logic outside the view, and should be a work of a model. Here is a cleaner view though.
<% #data['body']['predictions']['direction']['prediction'].each do |x| %>
<% x.each do |k, v| %>
<h4><%= v %></h4>
<% end %>
<% end %>

Looks like you are ignoring the keys which don't have nested values say title and a , b .
"title"=>"xxxx"
},
"a"=>"xx",
"b"=>"x"
},
Your final code should look like
if #data["body"]["predictions"].present?
#data["body"]["predictions"].each do |p|
p.each do |d|
if d.kind_of? Hash
d.each do |k|
if k.kind_of? Array
k.each do |x|
if x.kind_of? Array
x.each do |y|
if y.kind_of? Hash
puts y["epochTime"]
end
end
end
end
end
end
end
end
end
end
The above code is ugly but you are C++ programmmer , you might like it :P

The whole hash things was getting out of hand as I had constantly detect each one's present and loop through it, so As Tin man suggested, I used XML 'nokogiri' and then used .css method to detect if it existed and looped through it, since original response was in xml.
#doc.css('predictions').each do |predictions_node|
predictions_node.css('direction').each do |direction_node|
direction_node.css('prediction').each do |prediction|
// stuff here
Thanks for your time and consideration.

Related

Working with JSON in Rails

I have a table called "Weights" that holds a user's weight for a specific day. I can retrieve all relevant data as JSON with the following line of code in my controller's index action:
#weights = Weight.where(:user_id => current_user.id).to_json
The output then looks like:
[{"id":72,"user_id":71,"kilograms":94.0,"day":"2016-06-03","created_at":"2016-06-03T06:58:35.139Z","updated_at":"2016-06-03T06:58:35.139Z"},{"id":75,"user_id":71,"kilograms":34.0,"day":"2016-06-02","created_at":"2016-06-03T13:05:49.862Z","updated_at":"2016-06-03T13:05:49.862Z"},{"id":76,"user_id":71,"kilograms":56.0,"day":"2016-05-29","created_at":"2016-06-03T13:06:01.747Z","updated_at":"2016-06-03T13:06:01.747Z"}]
However, what I would need is an output that looks like:
{2016-06-03 => 94.0, 2016-06-02 => 34.0, 2016-05-29 => 56.0}
How can I achieve this? (I just started coding so I'm sorry if this is a really noob question)
Many thanks.
UPDATE My request refers to a chart I want to display using Chartkick. The documentation says:
Times can be a time, a timestamp, or a string (strings are parsed)
<%= line_chart({20.day.ago => 5, 1368174456 => 4, "2013-05-07 00:00:00 UTC" => 7}) %>
My weights_controller.rb index action now
def index
result = {}
Weight.where(:user_id => current_user.id).each do |weight|
result[weight.day] = weight.kilograms
end
end
Thus I need my data in format described above.
Let try this:
#result = {}
Weight.where(:user_id => current_user.id).each do |weight|
result[weight.day] = weight.kilograms
end
Now the result will be a hash:
{'2016-06-03' => 94.0, '2016-06-02' => 34.0, '2016-05-29' => 56.0}
If you want result to be json:
#result.to_json
Update Simply use it in the view for example:
<% #result.each do |day, kg| %>
<p>Day: <%= day %>, Kg: <%= kg %><p>
<% end %>

Rails traverse deep array of hashes

I got this very confusing array of hashes as an API response.
http://jsfiddle.net/PP9N5/
( the full response is massive. Posting only a part of it but it covers all elements of the response)
How can I get to "airlines".
I tried this
<% #flight["air_search_result"]["onward_solutions"]["solution"].each do|h| %>
<strong><%=h["pricing_summary"]["total_fare"] %></strong> -
<% h["flights"]["flight"]["segments"]["segment"].each do |s| %>
<%= s['airline'] %>
<% end %> <br> <hr>
<% end %>
And I get this error
can't convert String into Integer
I did some modifications like
<%= h["flights"]["flight"]["segments"]["segment"].first["airline"] %>
Error received - can't convert String into Integer
and
<%= h["flights"]["flight"]["segments"]["segment"][0]["airline"] %>
Error received - undefined method '[]' for nil:NilClass
Isnt there a simple way, like I say to find a key "airline" and for that key it returns its value. I stumbled upon this link, though I dont get any error, I also dont get any result.
Thanks.
UPDATE
I did this
<% h["flights"]["flight"]["segments"]["segment"].each do |o,p| %>
<% if o=="airline" %> <%= p %> <% end %>
<% end %> <br> <hr>
<% end %>
I can get few values of airlines where inside segment there is no array.
For eg, i can get where departure_date_time is 2014-07-07T07:10:00, index = 5.
http://jsfiddle.net/PP9N5/1/ (scroll down)
Here is some code you can add which will extract all keys equal the parameter in any Hash within your Hash:
class Hash
def deep_find(query, &block)
flat_map do |key, value|
if key == query
yield value if block_given?
[value]
elsif value.is_a? Hash
value.deep_find(query, &block)
elsif value.is_a? Array
value.select { |i| i.is_a? Hash }.flat_map { |h| h.deep_find(query, &block) }
end
end
end
end
Example:
hash = {"h" => [{ 'x' => [1, 5] }, { 'x' => 2 }, { 'f' => { 'x' => [3, 4] } }], 'x' => 6 }
hash.deep_find('x') { |x| puts "#{x}" }
# [1, 5]
# 2
# [3, 4]
# 6
# => [[1, 5], 2, [3, 4], 6]
it's a tipical problem :D
Replace "=>" for ":" and render.
your_json = {.....}
your_json.gsub("=>", ":")
puts your_json
You can validate a JSON before to work it with http://jsonlint.com/.

Ruby looping through a specific array?

Is there a way to loop through a specific array?
For example, user.org_names returns:
["NEW", "Gold", "HEALTH SPRING"] ["Text Illinois"] ["Star Gold"] ["NEW", "Star Gold"] ["NEW", "Star Gold", "HEALTH SPRING"] ["Star Gold"] ["Star Gold"] ["Text Illinois", "Star Text", "Star Gold"] ["Text Illinois", "HEALTH SPRING"] ["NEW", "Star Gold", "Star Text"]
Now, I want to loop only through the fourth array ["NEW", "Star Gold"].
Is that a possibility in Ruby? I couldn't find such a feature.
You can use the basic array notation [] with the index as argument to get the value:
user.org_names[3] # get the 4th element of the array returned
# returns nil if does not exists
In your case, if you want to loop on the 4th element:
fourth_element = user.org_names[3]
fourth_element.each do |element|
# use element
end if fourth_element.present?
This behaves the same as:
fourth_element = user.org_names[3]
if fourth_element.present?
fourth_element.each do |element|
# use element
end
end
if after the end
1.9.3p489 :006 > [1,2,3].each do |n|
1.9.3p489 :007 > puts n
1.9.3p489 :008?> end if false
=> nil
Basically the same as doing:
[1,2,3].each{ |n| puts n } if false
But using a do/end syntax and multi-line
You can do that this way
user.org_names[3].each do |element|
puts element
end
If this is an array of arrays, maybe you could get the fourth element (user.org_names[3]) of the array and loop through it like this:
<% i = 0 %>
<% user.org_names[3].each do |a| %>
<% a[i] %>
<% i+=1 %>
<% end %>

how can Arrange rails params order

when i look at my console after submitting a form i can see like
Parameters: {"authenticity_token"=>"l0dqmb95MydzCWMugWdYt/2bGYyRyDF5ZfOGjrKhjfc=", "project_id"=>"second", "esthour"=>{"nonmodulhours_attributes"=>{"0"=>{"nonmodul_id"=>"61", "nonmodul_est_hours"=>"1"}, "1"=>{"nonmodul_id"=>"62", "nonmodul_est_hours"=>"9"}, "2"=>{"nonmodul_id"=>"63", "nonmodul_est_hours"=>""}}, "modul1hours_attributes"=>{"0"=>{"modul1_est_hours"=>"8", "modul1_id"=>"25"}, "1"=>{"modul1_est_hours"=>"", "modul1_id"=>"26"}**, "2"=>{"modul1_est_hours"=>"88", "modul1_id"=>"27"}}**, "ecommerce_est_hours"=>"", "modulhours_attributes"=>{"0"=>{"modul_est_hours"=>"8", "modul_id"=>"53"}, "1"=>{"modul_est_hours"=>"1", "modul_id"=>"54"}, "2"=>{"modul_est_hours"=>"8", "modul_id"=>"55"}}, "cms_est_hours"=>"", "nonmodul1hours_attributes"=>{"0"=>{"nonmodul1_id"=>"25", "nonmodul1_est_hours"=>"2"}, "1"=>{"nonmodul1_id"=>"26", "nonmodul1_est_hours"=>""}, "2"=>{"nonmodul1_id"=>"27", "nonmodul1_est_hours"=>"5"}}, "rfp_id"=>"35"}, "commit"=>"Add Todo", "utf8"=>"✓"}
here how can i arrange the attributes like line
"2"=>{"modul1_est_hours"=>"88", "modul1_id"=>"27"}}
to
"2"=>{ "modul1_id"=>"27","modul1_est_hours"=>"88",}}
**mean modul1_id before modul1_est_hours
form.html.erb**
<% #m1.map(&:id).each do |id|%>
<%= modul1(id) %> <%= f.hidden_field :modul1_id, :value => id %>
<%= f.number_field :modul1_est_hours, :size => 30 %>
</tr>
<% end %>
Edit
def get_issue_attribute_param1(u)
u.each do |key, value|
value.is_a?(Hash) ? get_issue_attribute_param1(value) : update_issue(key,value)
end
end
def update_issue(q,p)
if q.include?("_")
q1 = q.split("_")
q0 = q1[0]
if q1[0].include?("modul") && q1[1] == "id"
$id_map = p
puts $id_map
end
end
end
Here you go(in irb):
a = {"modul1_est_hours"=>"88", "modul1_id"=>"27"}
=> {"modul1_est_hours"=>"88", "modul1_id"=>"27"}
Hash[a.sort{|x,y| y.first <=> x.first }]
=> {"modul1_id"=>"27", "modul1_est_hours"=>"88"}
But, as everybody pointed out. If you could tell what you're trying to do, or what do you want with this? Then maybe what you're looking for maybe little more easy to understand and answer. :)
Edit
Here are the updated methods:
def get_issue_attribute_param1(params)
ids = []
params["esthour"].select{|hour| hour.include?('modul') }.each_pair do |key, value|
ids << update_issue(value)
end unless params["esthour"].nil?
ids # will have array of array like this: [["61", "62", "63"], ["25", "26", "27"], ["53", "54", "55"], ["25", "26", "27"]] for which you can do: `.flatten`
end
def update_issue(id_with_hours)
id_with_hours.values.map{|m| m.select{|v| v.include?('id') } }.map(&:values).flatten
end
Though I am not clear for what purpose you're using $id_map and hence I had to leave that scenario for you to handle. :)
I hope it helps.

How can I collapse this very repetitive Ruby/Rails code?

I've got two small structural issues that I'm not sure how to handle given my relative newbie-ness with RoR.
First issue: In one of my views, I have code that looks like this:
<ul style="list-style-type: circle">
<li><%= #apples.size %> apples</li>
<li><%= #oranges.size %> oranges</li>
<li><%= #bananas.size %> bananas</li>
<li><%= #grapefruits.size %> grapefruits</li>
</ul>
Is it possible to refactor this so that I only need to iterate once over some list of different kinds of fruit, and have the appropriate <li>'s be automatically generated? Edit: I forgot to add that #apples, #oranges, etc., might be nil. Is there an idiomatic way to handle that?
Second issue: In my controller, I have code that looks like this:
#apples = Apple.find(:all)
#apples.each { |apple| apple.do_stuff(:xyz) }
#bananas = Banana.find(:all)
#bananas.each = { |banana| banana.do_stuff(:xyz) }
# ... &c
As you can see, the same operation is invoked many times in exactly the same way. Is there a way to shorten this to something like [Apple.find(:all), ...].each { |fruit| ... } and have that work instead?
Thanks very much for your help!
I'd do this in a helper
def fruit_size(fruit)
list = #fruits[fruit]
return if list.empty?
content_tag(:li, "#{list.size} #{fruit}")
end
And this in the view:
<% ["apples", "oranges", "bananas", .....].each do |fruit| %>
<%= fruit_size(fruit)
<% end %>
In your controller:
#fruits = {}
["apples", "oranges", "bananas", ......].each do |fruit|
#fruits[fruit] = fruit.classify.constantize.find(:all).each {|record|
record.whatever_here
end
end
It makes sense to store all the items in a hash, #fruits, so that you don't have to use instance_variable_get and stuff.
Perhaps you also want to define that array somewhere, so that you don't have to repeat it in the controller and in the view. Let's pretend that you have a fruit model.
class Fruit < ActiveRecord::Base
FRUITS = ["apples", "oranges", "bananas", ....]
end
Then, use Fruit::FRUITS in the view and controller.
For the first part:
#li = ''
[#apples, #oranges, #bananas, #grapefruit].each{|fruit|
#li << "<li>#{fruit.size}</li>"}
<ul style="list-style-type: circle">
<%=#li%>
</ul>
You can actually do it pretty simply.
In your controller:
def whatever
#fruits = {
:apples => Apple.find(:all).each{ |a| a.do_stuff(:xyz) },
:bananas => Banana.find(:all).each{ |a| a.do_stuff(:xyz) } # ...
}
end
In your view:
<% #fruits.each |k, v| %>
<li><%= v.nil? ? 0 : v.size %> <%= k.to_s %></li>
<% end %>
Although you might want to consider whether do_stuff is something that could be done via a more complex finder, or by named scope.

Resources