GithubHelp home page GithubHelp logo

meteorologist's Introduction

Meteorologist

There is a Getting Started video on Canvas. Go watch that first.

Setup

  • Ensure that this repo has been forked to your own GitHub account.
  • Set up a Cloud9 workspace as usual.
  • bin/setup
  • Run Project.
  • Go to the live app in Chrome.

Introduction

In this project, you will practice working with Arrays and Hashes by pulling data from external services like Google Maps. You will build an application that, given a street address, tells the user the weather forecast.

In order to achieve this, our first task will be to exchange a street address for a latitude/longitude pair using Google's Geocoding API.

We will send a location in a remarkably flexible, "English-y" format, the kind of thing we are allowed to type into a Google Maps search (e.g., "the corner of 58th and Woodlawn"), and the Geocoding API will respond with an exact latitude and longitude (along with other things) in JSON format.

Getting Started

Any time you are trying to develop a proof of concept of an app that needs external API data, the first step is researching the API and finding out if the information you need is available.

For us, that translates to: is there a URL that I can paste into my browser's address bar that will give back JSON (JavaScript Object Notation) that has the data I need? If so, we're good; Ruby and Rails makes the rest easy.

First, let's install a Chrome Extension called JSONView that makes working with JSON easier:

https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc?hl=en

This will indent the JSON nicely and allow you to fold and unfold nested elements.

Find an example

Now, we have to research the API and find the correct URL to paste into our address bar to get back the JSON that we want. Usually, we have to start at the API Documentation. For the Geocoding API, the full docs are here:

https://developers.google.com/maps/documentation/geocoding/

but, as usual with technical documentation, it's best once you skim the intro to head straight for the examples:

https://developers.google.com/maps/documentation/geocoding/start#geocoding-request-and-response-latitudelongitude-lookup

The first example they give is

https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA

(I have removed the part about the API key from the end of the URL; we don't need one, for now.) Paste that URL into a Chrome tab; you should see something like this:

I folded away the address_components section to make the value of the geometry key stand out, since that is where our target lives: the lat and lng keys within the location hash. Notice that JSON uses curly braces for Hashes and square brackets for Arrays just like Ruby does.

Alright, now that we have the data we need showing up in the browser window, what's next? First of all, we should be sure that we can customize this example request to get data that we care about. So how would we get the coordinates of "the corner of Foster and Sheridan"? Give it a try.


It turns out we need to replace the part of the URL between the ?address= and the & with the address we want Geocoded, but with one catch: spaces are not legal in URLs, so we have to encode them. One way to encode them can be seen in Google's example, with +s, so the following works:

Ruby

Great! Now we know the exact data we want is available through the API. Now, how do we get it into our application? Fortunately, Ruby comes with some powerful built-in functionality that will help us with this. First, we need Ruby to read the URL that has the JSON we want, just like Chrome did. Chrome has an address bar we can paste the URL in to; how can we tell Ruby to go open a page on the Internet?

Fire up a Rails Console session:

  • Open a Terminal window (click the circled green + in Cloud9).
  • rails console (or rails c for short)

Enter the following command: require 'open-uri'. This command loads a method called open from the Ruby Standard Library (which is part of Ruby but isn't loaded up by default because not every single Ruby script needs to open Internet pages). If the command returns false, don't worry; that just means that you already have it loaded.

The open method takes one argument: a String containing the URL of a page on the internet.

Create a variable called url (or whatever you want) and store within it a String containing the URL we discovered that has the data we want. (Don't forget the double-quotes around your string!)

Copy the URL directly from the address bar of your Chrome tab. Then, pass that variable as an argument to the open method:

open(url).read

Note: Your rails console will look different than the screenshots below. You might have a different prompt, colored output, and better indentation since you are using a more powerful version called Pry.

Important: To scroll through long output in rails console, you can use return to scroll one line at a time, Space to scroll one page at a time, or Q to just get back to the prompt to enter a new Ruby expression.

What just happened? We opened the page at url, and the return value was the HTTP response. The HTTP response is actually a complicated object, with headers and status codes and other things we haven't talked about yet.

All we really want is the body of the response, the stuff that shows up in the browser window, so we used the .read method to pull that out. However, we just dropped that string on the ground; let's instead store the result in a variable called raw_data:

raw_data = open(url).read

Alright! We just used Ruby to open up a connection over the Internet to Google's servers, placed a request for them to translate our address into a latitude and longitude, and received a response! That's a big deal, folks. However, the response is hideous. How in the world are we going to pull out the latitude and longitude values from that thing?

Let's start to explore it:

That's a little nicer to look at. But still, it's going to be quite hard to get to the latitude and longitude. We could explore the String class documentation and find some methods that might help us scan through raw_data for "lat", perhaps. But then what? We could probably figure it out, but there's a much better way.

Fortunately, Ruby provides a class called JSON, similar to the CSV class, which makes parsing a string that has data in JSON format a snap:

parsed_data = JSON.parse(raw_data)

Now, explore the resulting object:

Look! Hash rockets! We've converted a cumbersome JSON string into a beautiful, friendly Ruby Hash. Now, if I want to get down to the latitude and longitude, how would I do it? Well, remember, we already got a hint back when we first looked at the data in Chrome:

parsed_data is a Hash (don't believe me? do parsed_data.class and parsed_data.keys). The data we want looks like it is inside the key "results". So lets step in one level deep:

It doesn't look very much better, but we're closer to our goal. What class of object is in results? It's no longer a Hash; we can tell both in Rails Console and from looking at JSONView that it is an Array. Let's go one level deeper by getting the first element:

Alright, so we now have a Hash in first that has a key called "geometry", which, as we learned from our initial research above, is what contains our target. Let's keep going:

Woo! We made it all the way down to what we want. Phew! Now, I did it in a bunch of tiny steps, which might have made it seem complicated, but we could also have just done it in one step:

I prefer working in small steps and peeling one layer off at a time while I am exploring. But, the entire program boils down to just three lines!

parsed_data = JSON.parse(open(url).read)
latitude = parsed_data["results"][0]["geometry"]["location"]["lat"]
longitude = parsed_data["results"][0]["geometry"]["location"]["lng"]

Now that we've explored in the console, it's time to take these three lines (or something like them, anyway) and write some permanent programs...

Part 1: Street → Coords

Now that we've seen how to retrieve information from a URL using Ruby, let's plug it in to a real application.

I have started you off with three forms:

And three actions which process these form inputs and render results:

  • app/controllers/geocoding_controller.rb
  • app/controllers/forecast_controller.rb
  • app/controllers/meteorologist_controller.rb

We'll be working on Street → Coords first.

Open the file app/controllers/geocoding_controller.rb. Your job is to write some code in the street_to_coords method, where indicated, and put the correct value in the @latitude and @longitude variables.

If I type in 5807 S Woodlawn Ave at the Street → Coords form, I should see something like

Street Address
5807 S Woodlawn Ave
Latitude
41.7896234
Longitude
-87.5964137

Part 2: Coords → Weather

Next, in app/controllers/forecast_controller.rb, you will do something similar; but instead of using Google's Geocoding API, you will use The Forecast API. We will exchange a latitude/longitude pair for weather information. Forecast is an amazing API that gives you minute-by-minute meteorological information.

They released an iOS app, Dark Sky, to demonstrate the power of their API, and it instantly became a smash hit. The API is not entirely free, but we get 1,000 calls per day to play around with.

Step 1 when working with any API is research. What is the URL of the page that has the data we want, preferably in JSON format?

Let's head over to Forecast's API documentation. First, we must register as developers:

You need not provide a real email address, if you don't want to. Once you register, you will be given an example link with your own personal API key inserted in a variable path segment:

Find an example

Click the example link and check out the data they provide. Scroll up and down and get a feel for it:

It's pretty amazingly detailed data; it tells us current conditions, along with minute-by-minute conditions for the next hour, hour-by-hour conditions for the next day or so, etc.

But first, can we customize the example to get data relevant to us? Plug in some coordinates that you fetched in street_to_coords and try it out.

Your job is to write some code in the coords_to_weather method, where indicated, and put the correct value in the instance variables at the end.

If I type in 41.78 and -87.59 at the Coords → Weather form , I should see something like

Latitude
41.78
Longitude
-87.59
Current Temperature
73.35
Current Summary
Clear
Outlook for next sixty minutes
Clear for the hour.
Outlook for next several hours
Partly cloudy tomorrow morning.
Outlook for next several days
No precipitation throughout the week, with temperatures falling to 62°F on Tuesday.

Note: Forecast does not have data for every lat/lng combination; some geographies will return nils. If you run into issues, you can try Ruby 2.3's handy new Hash#dig method:

parsed_results.dig("minutely", "summary")

rather than

parsed_results["minutely"]["summary"]

The latter, if parsed_results["minutely"] is nil, will throw an error complaining that you can't do nil["summary"]. The former will handle the issue more gracefully. Read more in this StackOverflow thread.

Part 3: Address to Weather

Finally, pull it all together in app/controllers/meteorologist_controller.rb. Use both the Google Geocoding API and the Forecast API so that if I type in 5807 S Woodlawn Ave at the Street → Weather form, I should see something like

Here's the outlook for 5807 S Woodlawn Ave:

Current Temperature
73.35
Current Summary
Clear
Outlook for next sixty minutes
Clear for the hour.
Outlook for next several hours
Partly cloudy tomorrow morning.
Outlook for next several days
No precipitation throughout the week, with temperatures falling to 62°F on Tuesday.

Submission

Remember to make lots of commits as you work. Use the Continuous Integration workflow as usual to open a Pull Request to submit your work.

And ask lots of questions! Really. Ask early and often.

Good luck!

Optional Extra Exercises, for fun

Programmable Web (Easier)

Browse Programmable Web's API Directory and get inspired!

Bootstrap (Easier)

<link> to Bootstrap or a Bootswatch in the <head> of your pages (located in app/views/layouts/application.html.erb), and make things look prettier.

You can take Omnicalc as inspiration, or create something entirely new.

Future Forecast (Harder)

The Forecast API can take a third parameter in the URL, time:

https://developer.forecast.io/docs/v2#time_call

Add a feature that shows summaries for the next 14 days.

Google Map (Harder)

Embed a Google map in the view, centered on the provided address. Refer to the docs:

https://developers.google.com/maps/documentation/javascript/examples/map-simple

The key concept is, just like with Bootstrap, to first paste in the example markup and see if it works.

Then, replace whichever part of the static markup you want to with embedded Ruby tags that contain your dynamic values.

meteorologist's People

Contributors

raghubetina avatar bjblock avatar murugan-r avatar

Watchers

James Cloos avatar Elizabeth Campbell avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.