1

Objective: Parse data to display all the id's in the erb file

Problem: NoMethodError in DemoController#index due to this piece of code @x = obj[i]["id"]

When I replace the "i" in the above piece of code with a number, one id number displays which leads me to believe that the while loop is correct. It just doesn't understand what "i" is.

What am I doing wrong?

Here is my code for my Controller and View

demo_controller.rb

require 'rubygems'
require 'json'
require 'net/http'
require 'httparty'
class DemoController < ApplicationController

  respond_to :json
  $angelURI = "https://api.angel.co/1/jobs"

  def index
    response = HTTParty.get('https://api.angel.co/1/jobs/')
    obj = JSON.parse(response.body)["jobs"]
    arraylength = obj.length

    i = 0
    while i <= arraylength do
      @x = obj[i]["id"]
      i += 1

    end


  end
end

index.html.erb

<%=@x%>

5 Answers 5

2
  1. You are assigning a value to the same @x variable at each level of your loop - this will end with @x having the value of the last id - is that the intended behavior ?

  2. I don't see something weird with your array right now, but Ruby tend to favor using each over for:

    obj.each do |elem|
      @x = elem["id"]
    end
    

Upate: Following zishe good catch about the loop, using each also avoid that kind of question ("do I need to go to the ith element or stop at the ith-1").

Sign up to request clarification or add additional context in comments.

Comments

1

By combining best of answers we get:

@x = []
obj.each do |job|
  @x << job["id"]
end

1 Comment

This got me just what I wanted. Thanks so much!
1

i is a counter in while loop, it's basics. I think you looping to more, change <= on < in this:

i = 0
while i < arraylength do
  @x = obj[i]["id"]
  i += 1
end

Or better do like Martin suggests.

1 Comment

I overlooked the "<" Thanks so much for catching this!
1

So, you have a off-by-one error: your while loop runs too far (because of the <=). Simple solution: use each (so you do not have to maintain a counter yourself --why make it hard). But on top, I would propose to add a file in lib that will do the parsing of the page.

So, e.g. add a file called lib/jobs_parser.rb that contains something like

require 'httparty'

module JobsParser

  ANGEL_JOBS_URI = "https://api.angel.co/1/jobs"

  def all_job_ids
    all_jobs.map{|j| j["id"]} 
  end

  def all_jobs
    response = HTTParty.get(ANGEL_JOBS_URI)
    jobs = JSON.parse(response.body)["jobs"]
  end
end

What do I do here: the map generates an array containing just the "id" field. I think it makes more sense, on this level to keep the complete array of jobs or ids.

Note: I drastically shortened the list require statements, most should be auto-required via your Gemfile.

And then in your controller you can write:

class DemoController < ApplicationController

  def index
    all_job_ids = JobsParser.all_job_ids
    @x = all_job_ids.last
  end

end

and your view remains the same :)

This has the advantage that you can simply test the JobsParser, through tests, or manually in the rails console, and that your code is a bit more readable.

1 Comment

Wow! This is totally helpful to making a helper file. I'm definitely going to try it out. Thanks so much for the clarity!
0

You have a off-by-one error in your code. Basically, you are looping over the array and are then trying to access one more element than is in the array, which is then returned as nil and naturally doesn't act as a Hash.

Say your obj is an array with 3 elements, thus arraylength is three. You are now fetching 4 elements from the array, the elements with the indexes of 0, 1, 2, and 3. As you only have the 3 elements 0..2, the last one obj[3] doesn't exist.

To keep your existing code, you could change your loop to read as follows:

while i < arraylength do
  #...
end

However, to just get the id of the last element in your array, it is much clearer (and much faster) to just use idiomatic ruby and write your whole algorithm as

def index
  response = HTTParty.get('https://api.angel.co/1/jobs/')
  jobs = JSON.parse(response.body)["jobs"]

  @x = jobs.last["id"]
end

1 Comment

Didn't know about ".last" Thanks for the tip!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.