Search code examples
rubyrubymotion

Bubblewrap HTTP -> Table View; method returns bubblewrap query instead of response data


I'm trying out Rubymotion and can't seem to do figure how to accomplish what seems like a simple task.

I've set up a UITableView for a directory of people. I've created a rails back end that returns json.

Person model has a get_people class method defined:

def self.get_people
  BubbleWrap::HTTP.get("http://myapp.com/api.json") do |response|
    @people = BW::JSON.parse(response.body.to_str)
    # p @people prints [{"id"=>10, "name"=>"Sam"}, {etc}] to the console
  end
end

In the directory_controller I just want to set an instance variable for @data to the array that my endpoint returns such that I can populate the table view.

I am trying to do @data = Person.get_people in viewDidLoad, but am getting an error message that indicates the BW response object is being passed instead: undefined methodcount' for #BubbleWrap::HTTP::Query:0x8d04650 ...> (NoMethodError)`

So if I hard code my array into the get_people method after the BW response block everything works fine. But I find that I am also unable to persist an instance variable through the close of the BW respond block.

def self.get_people
  BubbleWrap::HTTP.get("http://myapp.com/api.json") do |response|
    @people = BW::JSON.parse(response.body.to_str)
  end
  p @people #prints nil to the console
  # hard coding [{"id"=>10, "name"=>"Sam"}, {etc}] here puts my data in the table view correctly
end

What am I missing here? How do I get this data out of bubblewrap's response object and in to a usable form to pass to my controllers?


Solution

  • As explained in the BW documentation "BW::HTTP wraps NSURLRequest, NSURLConnection and friends to provide Ruby developers with a more familiar and easier to use API. The API uses async calls and blocks to stay as simple as possible."

    Due to async nature of the call, in your 2nd snippet you are printing @people before you actually update it. THe right way is to pass the new data to the UI after parsing ended (say for instance @table.reloadData() if @people array is supposed to be displayed in a UITableView).

    Here's an example:

    def get_people
        BubbleWrap::HTTP.get("http://myapp.com/api.json") do |response|
            @people  = BW::JSON.parse(response.body.to_str)
            update_result()
        end
    end
    
    def update_result()
        p  @people
        # do stuff with the updated content in @people
    end
    

    Find a more complex use case with a more elaborate explanation at RubyMotion async programming with BubbleWrap