The MARTA API
Real-Time Bus Tracker
The MARTA Bus Real-time Data RESTful Web Service provides information about the real-time location and schedule adherence for active buses on the MARTA system.
Opened to developers in October 2012, the feed works in conjunction with schedule data provided in MARTA's GTFS feed.
What Does That Mean For Us?
Through the API we are allowed access to data concerning all buses currently on the road wherever the MARTA (bus) system runs.
This is a sample of the data we are pulling in:
{"ADHERENCE":"-4", "BLOCKID":"348", "BLOCK_ABBR":"32-7", "DIRECTION":"Southbound", "LATITUDE":"33.6891136", "LONGITUDE":"-84.3370348", "MSGTIME":"12\/2\/2014 7:07:26 AM", "ROUTE":"32", "STOPID":"151060", "TIMEPOINT":"Metro Transitional Center", "TRIPID":"4347502","VEHICLE":"2403"}
We
Data
Look at all the data we get to work with:
ADHERENCE: how late/early the bus is (in minutes)?
DIRECTION: which cardinal direction is the bus headed?
LATITUDE/LONGITUDE: exact coordinates of the bus!
ROUTE: the route number, obvi.
TIMEPOINT: the bus' next stop.
VEHICLE: the ID number of that particular bus.
What We'll Do With the Data
We can create a Rails app that will take an address (or approximate) from the user, and let them know if there is a bus anywhere nearby.
We'll be using the Geocoder gem to pinpoint the User's longitude/latitude.
First Things First...
Let's create a new project, with one resource: Location
$ rails new marta_near_me
$ cd marta_near_me
$ rails g scaffold Location address:string city:string latitude:float longitude:float
And don't forget to...
Remember, for Geocoder to work we need the attributes of latitude and longitude, both as floats.
Views We'll Use
Let's make this app all about the New and Show pages.
Location/New will be our root page.
Rails.application.routes.draw do
root 'locations#new'
resources :locations
end
new and _form Views
<h1>Is a Bus Nearby?</h1>
<p>
Give us your address or
approximate location (<em>I'm at the
corner of...</em>), and we'll let you
know if there's a bus in the vicinty!
</p>
<%= render 'form' %>
<!-- lines 1-12 remain the same;
but in the fields area we'll
be more specific on our label
for the address field, and we'll
delete the fields for latitude
and longitude - Geocoder will
take care of those for us!
-->
<div class="field">
Address or Approximate Location:<br>
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :city %><br>
<%= f.text_field :city %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
location/new.html.erb
location/_form.html.erb
Showing the Buses
If there are buses nearby, we'll have them saved in an array and display their vital info for the User.
<p id="notice"><%= notice %></p>
<h2>You Are Currently Standing At...</h2>
<p>
<!-- my_location will be defined
in the model, as the combination
of address and city -->
<%= @location.my_location %>
</p>
<h2>The Closest Buses Are...</h2>
<!-- What if there are no buses nearby? -->
<% if @bus_count == 0 %>
<p>
...not really that close. It may be best to just use Uber.
</p>
<% end %>
<!-- But if there are some buses in the vicinty... -->
<% @nearby_buses.each do |bus| %>
<p>
<!-- We'll show the Route #, Vehicle # and
where the bus' next stop is. -->
<strong>Route</strong>: <%= bus["ROUTE"] %><br />
<strong>Vehicle #</strong>: <%= bus["VEHICLE"] %><br />
<strong>Next Stop:</strong>: <%= bus["TIMEPOINT"] %><br />
</p>
<% end %>
<!-- Leave a link to the edit page,
so the User can move about and try
again. -->
<%= link_to "Actually, I'm at...", edit_location_path(@location) %>
location/show.html.erb
Now to the Back End!
We've got the Front End complete
(maybe it could use some styling).
Let's power this app in the Back End.
Our next steps will be to visit these files:
1. Gemfile
2. location.rb
3. locations_controller.rb
4. locations_helper.rb
Geocoder Gem
We'll start by adding the gem to our Gemfile...
gem 'geocoder'
And running bundle in Terminal...
$ bundle install
Geocoder & The Model
Next, we'll set up Geocoder's lat/long magic in the Location model.
location.rb
class Location < ActiveRecord::Base
geocoded_by :my_location
after_validation :geocode
# here, behind the scenes,
# we will combine the address
# and city given to use by the User,
# while also adding the state
# (because obviously, for MARTA, it's
# only going to be GA), and Geocode that!
def my_location
"#{address}, #{city}, GA"
end
end
Gain Control(ler)
Next we'll visit the Locations controller.
We're particularly interested in the show action.
locations_controller.rb
def show
# below is the URL or the MARTA API,
# from this is where we pull the data
# of all active MARTA buses
source = 'http://developer.itsmarta.com/BRDRestService/BRDRestService.svc/GetAllBus'
# we'll need to parse the data into an array of hashes,
# following method will be defined in the Helper
@buses = fetch_url_data(source)
@bus_count = 0
@nearby_buses = []
@buses.each do |bus|
# once again we'll use a method defined in the Helper
if nearby(@location.longitude, @location.latitude, bus["LONGITUDE"].to_f, bus["LATITUDE"].to_f)
@bus_count += 1
@nearby_buses.push(bus)
end
end
end
If You Need Some Help
Let's visit the Application Helper now (you could also do this in the Location Helper) and define the methods we used in the Controller.
application_helper.rb
module ApplicationHelper
# In the following method, we parse the data
# to store it in an array of hashes (each bus a hash)
# I wouldn't expect you to come up with code all on
# your own it was given to me by a wiser coder, and
# now I hand it down to you, young Rails padowans...
def fetch_url_data(source)
http = Net::HTTP.get_response(URI.parse(source))
data = http.body
response = JSON.parse(data)
return response
end
# This method will compare the lat/longs of the User
# and each bus, to see if they're close to each other
# In this case, "nearby" means within .01 of a degree.
def nearby(lng1, lat1, lng2, lat2)
if (lng1 - lng2).abs <= 0.01 && (lat1 - lat2).abs <= 0.01
return true
else
return false
end
end
end
One Last Step...
We'll need to make sure the Locations controller is even looking at the Application Helper.
locations_controller.rb
class LocationsController < ApplicationController
before_action :set_location, only: [:show, :edit, :update, :destroy]
include ApplicationHelper
# and then the rest of the file...
Let's Test It Out!
localhost:3000
(/locations/new)
localhost:3000/locations/show/1
How Can We Improve This App?
MARTA only runs in a select amount of cities - we could give the User a dropdown of cities to choose from.
Would a map showing where the User and the nearby Buses are located being helpful to the User?
Map It!
We just learned about the Google Maps API, why not use it in this app as well!
The Marta API
By argroch
The Marta API
Using MARTA's real-time API (plus Google Maps API) to power to Rails app.
- 1,595