Homework for 8A

Review

Topics Covered: Putting MVC together; building an API app; taking off the scaffolding training wheels

Conceptual Steps

  1. Visualize the data your application will need to show or manipulate. In this case, it was stories. Today, we used an API to get our data; in the future, we'll get our data from our own database.
  2. Think about what you want to do with those things. Common actions are look at them, edit them, delete them—in other words, basic CRUD actions. Other things in this case might be to filter by title, or rank by score. These will become your controller methods.
  3. Think about which data will go on what page—we did this with the Twitter and Facebook exercises yesterday. These will become your views. For today, we had one simple view: showing all the stories for the index action.

Coding Steps

For review purposes, here are the list of steps we did today (the order may seem different because we jumped around a bit during class—please check the video if these steps confuse you):

  1. rails new reddit_rails
  2. cd reddit_rails
  3. Create a story.rb file in app/models and add the code to create a model (something that looks like class Story < ActiveRecord::Base ... end
  4. Create a stories_controller.rb controller in app/controllers (it should have something like class StoriesController < ApplicationController ... end)
  5. Give it the methods you thought about in step 2 above (in our case, we made index)
  6. Create a route for your action in config/routes.rb
  7. Create a view index.html.erb in app/views/stories (you'll have to make a folder called stories). Why do we name it index? Because your action is called index. Rails renders the view with the same name as the action. We'll learn how to change that later.
  8. Now you should be able to see your view in your route. Woohoo only 10 steps!


Exercises

E1: Conceptual Review

Why are we not using scaffolding? Why do we not want to use it all the time?

E2: Open Source Democracy

Now we're going to write an app that does what our Terminal code for using the data.gov API did. In d8, start by creating new rails app called petitions_rails. If you've lost the code from before, you can find it here.

Setup

For this app to work, remember that we needed to install the gems 'rest-client' and 'json'. The way Rails manages this is in the Gemfile, stored right in first directory. Right now, it looks something like

source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# ...

At the end of the file, go ahead and add gem 'json' and gem 'rest-client' on their own lines. Then, back in Terminal, run bundle install. What that does is basically run gem install for each of the gems in the Gemfile.

Models (Steps 3 from the list at the top of the page)

Now we want to think about what models our application is going to need. One of them should be fairly obvious: a Petition model. Go ahead and create that.

The Start of an Application (Steps 4-6)

Follow the steps in today's code along, and create a route that maps the URL /petitions to a controller (probably the PetitionsController), and create the necessary action (probably index). Make sure your route in config/routes.rb maps to that controller and action.

Now visit localhost:3000 and make sure your link works. Get it so there are no error messages, and it basically shows an empty page.

Now for Some Actual Logic (All the stuff in the code along, but in the model file)

Now you have to figure out where all the code we wrote last week goes. But this application is unique: we're not pulling data from our database, but from the data.gov API. We're going to create a get_petitions method that does just that.

class Petition < ActiveRecord::Base
  def self.get_petitions
    # your code here
  end
end

What should your code do? You want to get the data from the API, and return an array of hashes that contain all the information that we want. Your code should not puts anything—that's what your view is for! If I were to write pseudo-code, it might look like:

def self.get_petitions
  # Get JSON from API
  # Parse it into a hash
  # Get the relevant fields of the hash
  # Return an array of petitions
end

Back to the Controller

Start getting used to this workflow: Rails is a lot of switching between files, putting your code in the right place. What method should we call inside the index` action? What instance variable should you store that in?

Lastly, the View (Step 9)

Update your /app/views/petitions/index.html.erb file to render each of the petitions title, body, URL, deadline, status, created and siganture count. But don't let the date be something ugly like 1403920011, use some of Rails' built in methods to make it into something nice (this might help).

All in All

Now you should have a website that has two pages: a main page (URL /) that has a link to the /petitions page, and a petitions page (with URL /petitions) that shows the first five petitions on data.gov. Congrats, you've built your first somewhat useful website!!

E3 (Bonus!): One for All

A bit tougher now! Add the UI (user interface) and controller methods to be able to view just a single petition by clicking on it on the petitions page. The URL will probably looks something like /petitions/petition_id. (Hint: use a show action.) In order to do this, you'll have to use the params hash. We'll cover this in more detail next week, but for now, all you need to know is that if you define a route with :id where you expect the link to include the id number, the id given in the URL will be available as params[:id] as shown below.

# In config/routes.rb 
# :id is a placeholder where the URL will have a number
get '/petitions/:id' => 'petitions#show' 

# In app/views/petitions/index.html.erb
# the actual petition id is put in the URL. 
<% @petitions.each do |petition| %>
  <!-- Show the petition... -->
  <!-- Then add a link to see just this one -->
  <%= link_to 'Show', '/petitions/' + petition[:id] %>
<% end %>
# Note that in this case, id will look something like 50a3fd762f2c88cd65000015
# Why is it not something nice, like 1 or 8? Because we're not using our
# database yet, and this is how the petitions api works. 

# In app/controllers/petitions_controller.rb
# the params hash will now have a key :id which has the value of 1
def show
  @petition = Petition.get_petition(params[:id])
end

Note that now we're calling Petition.get_petition instead of Petition.get_petitions. get_petitions takes no arguments, and returns an array of petitions. get_petition should take one argument (the petition id), and returns one petition. How can we use the data.gov API to get just one petition, instead of an array? Hint—make sure to read thoroughly.

Your website works, but it always gives us just the last 5 petitions. It doesn't let us filter, or search, or any of the nice things the API allows us to do. Let's fix that.

E4 (Bonus!): Customize

In the same app, add the necessary user interface (meaning HTML/CSS in your views), controller methods and model methods that allow us to search through petitions, filter by status, or see more than 5. Then go sign one of them and participate in America's beautiful democracy.

E5 (Bonus!): Your own API

Using the steps above, turn the group API project you did on Day 4 into a Rails app. It may seem repetitive/redundant to do a third API app, but please trust us: repetition with Rails never hurts. If you feel its easy, start adding CSS in app/assets/stylesheets so that your website looks pretty!