I am getting JSON information from the Pivotal Tracker API, and I need to get certain info, instead of all the raw data. To do this, I used JSON.parse()
to convert the JSON to a Ruby array of hashes.
Now, I need to iterate through this array and only return the relevant hashes.
For example, I just want to return the primary_resources
hash that has a nested hash of:
"story_type" => "feature"
To do this, I wrote this code (response.body
is the data returned from the GET request):
@data = response.body
parsed = JSON.parse(@data)
puts parsed['primary_resources']['story_type']['feature']
When I run the script, I get this error:
no implicit conversion of String into Integer (TypeError)
It seems that it is iterating through an array of hashes and looking for an integer number of the array (like array[3]
or array[0]
), but that doesn't help me. I need to return all the hashes that have a nested hash :kind => story
in the primary resources hash.
I also tried to do this:
parsed.each do |entry|
puts entry['primary_resources']['story_Type']['feature']
end
and I got the same error.
Here is my full code:
require 'json'
require 'net/http'
require 'open-uri'
require 'openssl'
require 'active_support'
prompt = '> '
puts "What is the id of the Project you want to get data from?"
print prompt
project_id = STDIN.gets.chomp()
puts "What is the beginning date you want to return from? ex: 2014-07-02"
print prompt
date1 = STDIN.gets.chomp()
puts "What is the end date you want to return from? ex: 2014-07-16"
print prompt
date2 = STDIN.gets.chomp()
def scope(project_id, date1, date2)
uri = URI.parse("https://www.pivotaltracker.com/services/v5/projects/#{project_id}/activity?occurred_after=#{date1}T01:00:15Z&occurred_before=#{date2}T01:00:15Z&fields=primary_resources")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
request.add_field("X-TrackerToken", "*****************")
response = http.request(request)
@data = response.body
parsed = JSON.parse(@data)
puts parsed['primary_resources']['story_type']['feature']
# parsed.each do |entry|
# puts entry['primary_resources']['kind']['story']
# end
# puts parsed['primary_resources'].select { |r| r['story_type'].eql? 'feature' }
end
scope(project_id, date1, date2)
Here is some of the JSON response, without parsing (full response is too long, and really just the same response for like 15 other user stories):
What is the id of the Project you want to get data from?
> 961142
What is the beginning date you want to return from? ex: 2014-07-02
> 2014-07-02
What is the end date you want to return from? ex: 2014-07-16
> 2014-07-03
[
{
"primary_resources": [
{
"kind": "story",
"id": 74313670,
"name": "User can make an image fit inside the grid when viewing image detail and save it to case template. BUILD 146",
"story_type": "bug",
"url": "https://www.pivotaltracker.com/story/show/74313670"
}
],
"guid": "961142_3419",
"project_version": 3419
},
Here is some of the JSON response, after parsing (only showing first story for same reason as above):
What is the id of the Project you want to get data from?
> 961142
What is the beginning date you want to return from? ex: 2014-07-02
> 2014-07-02
What is the end date you want to return from? ex: 2014-07-16
> 2014-07-03
{"primary_resources"=>[{"kind"=>"story", "id"=>74313670, "name"=>"User can make an image fit inside the grid when viewing image detail and save it to case template. BUILD 146", "story_type"=>"bug", "url"=>"https://www.pivotaltracker.com/story/show/74313670"}], "guid"=>"961142_3419", "project_version"=>3419}
How can I iterate through this array of hashes and return only the ones of "story_type"=>"feature" ?
So according to the API documentation, what your code is receiving is an array of activities (or "activity-type resources"), each of which may contain a subarray (in "primary_resources") of the resources it affects.
I assume what you want as output from your program is an array of the activities that relate to a "feature"-type story, not an array of the affected stories themselves. If that's true, try this:
feature_story_activities = parsed.select do |activity|
activity.has_key?('primary_resources') &&
activity['primary_resources'].find do |resource|
resource['story_type'].eql?('feature')
end
end
puts feature_story_activities
This places in feature_story_activities
all the activities that
Specify a list of resources they affect, and
Affect at least one feature-type story.