This final section will take you into some of the more interesting sides of the Rails ecosystem which will help you reach beyond your own app and into the lives of your users via email or harness the powers of other apps via their APIs.
Step 1:
APIs and Building Your Own
Rails is really just an API itself… learn about APIs and how to turn your app into one
API Basics and Building Your Own
Introduction
Working with APIs is awesome and frustrating at the same time. On the one hand, interfacing with other applications out there can greatly improve the reach and “cool factor” of your own app. On the other, it involves lots of reading through documentation, figuring out authentication strategies, and parsing bad (or nonexistant) error messages.
Backing up, if you’re still unclear on what an API (Application Programming Interface) basically is, read the Skillcrush explanation and then read the first bit of this article to catch up.
“API” is an incredibly broad concept — any time your application talks to another application, that’s via some sort of API. The components within your own application, e.g. the different pieces of Rails, also talk to each other via APIs… they are more or less independent sub-applications that pass along the data they each need to complete their particular task. Everything’s an API in application-land!
When you build applications that have more dynamic front-end functionality (as complicated as single page Javascript applications or as simple as individual AJAX calls), they will talk to your Rails backend via your own APIs… which is really just an extra line or two of code to tell your controllers how to spit out JSON or XML instead of HTML.
In this lesson, we’ll cover how to build your own API. In the following lesson, we’ll cover how to interface with the APIs of other applications. The lessons are meant to give you a good onramp to learning this stuff but couldn’t possibly cover all the cases. Much of working with APIs is learning to read their documentation and figure out what they want.
Points to Ponder
Look through these now and then use them to test yourself after doing the assignment
- How Rails knows which type of file you are expecting back when you make an HTTP request.
- What is the purpose of the
#respond_to
method? - How do you return a User object but specify that you don’t want to include certain attributes (i.e. you can’t just return
User.first
)? - What are the two steps performed behind the scenes by the
#to_json
method? - How do you tell a controller action to render nothing but an error message?
- How do you build your own custom error messages?
- Why can’t you use session-based controller authentication methods if you want people to access your API programmatically?
- What is “Service Oriented Architecture?”
API Basics
Your Rails application is basically already an API, though you may not think of it that way. The web browser your user is running is also a program, so it is effectively making an API request to your Rails app whenever you request a new page. It just so happens that rendering HTML payloads is so common that we just bake that into our server-side programs as the default response type and consider everything else special.
Often, though, you want to make a request that doesn’t need to go through all the headache of using a web browser. You may not care how the page is structured (HTML), but instead just want to get straight to the data. Say you want to get a list of all users. You could go to something like http://yourapplication.com/users
which will probably run the #index
action and render a list of all the application’s users.
But why bother with all that extra stuff if all you want is the user list? The easiest thing to do would be to submit a request to that same URL asking for a JSON or XML response instead. If you set up your Rails controller properly, you will get back a simple JSON array object containing all the users. Sweet!
The same principle applies if you’re talking to external APIs… say you want to grab a user’s recent tweets from Twitter. You just need to tell your Rails app how to talk to Twitter’s API (e.g. authenticate yourself), submit the request, and handle the bunch of tweets that get returned.
Building APIs
You might want to make your Rails application entirely into an API backend for a front end webpage or you might just want to learn how to send out JSON when your front end requests it. This section won’t cover how to build a full featured RESTful API with authentication features… it is a gentle introduction to treating your application as an API.
The Basics
If you want your Rails app to return JSON instead of HTML, you need to tell your controller to do so. The cool thing is that the same controller action can return different things depending on whether your user is making a normal request from a browser or an API call from the command line. It determines which type of request is being made based on the extension of the file asked for, e.g. example.xml
or example.json
.
You can see which file type Rails thinks you want by checking your server log:
Started GET "/posts/new" for 127.0.0.1 at 2013-12-02 15:21:08 -0800
Processing by PostsController#new as HTML
The first line tells you which URL was requested and the second tells you where it’s going and how Rails is processing it. If you use a .json
extension, it looks like:
Started GET "/posts.json" for 127.0.0.1 at 2013-12-04 12:02:01 -0800
Processing by PostsController#index as JSON
If you’ve got a sample application running, try going to different URLs. If your controller isn’t ready for them, you may get an error, but you should be able to see what Rails thinks you’re asking for.
Rendering JSON or XML
Once you’ve decided that you want to respond to a request for JSON or XML, you need to tell your controller to render JSON or XML instead of HTML. The way to do so is by using the #respond_to
method:
class UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @users }
format.json { render :json => @users }
end
end
end
In this case, #respond_to
passes the block a format object, to which you can attach the appropriate rendering call. If you do nothing, html will render using the default Rails template as normal (in this case, app/views/index.html.erb
).
The #render
function is smart enough to know how to render a wide range of formats. When you pass it the key :json
, it will call #to_json
on the value, in this case @users
. That will make your Ruby object(s) into JSON strings, which can be transmitted to the requesting application.
And just like that, you’ve got yourself an API. Of course, things can get a bit more complicated if you want to do unusual things, but that’s the basics.
Specifying Attributes to Return
Let’s say you want to make sure you don’t return the user’s email address with the User object. In this case, you’ll want to edit which User attributes get returned by modifying what the #to_json
method does.
In the old days, you’d just overwrite your own version of #to_json
but these days you don’t need to do that — you will actually overwrite the #as_json
method instead. The #as_json
method is used by #to_json
, so modifying it will implicitly change the output of #to_json
, but in a very specific way.
#to_json
does two things — it runs #as_json
and gets back a hash of attributes which will need to be rendered as JSON. Then it will actually perform the rendering into JSON using ActiveSupport::json.encode
. So by modifying #as_json
, you’re more specifically targeting the part of the #to_json
method that you actually want to change.
In our case, we’ll do this by modifying #as_json
in our model to return only the attributes we want:
# app/models/user.rb
class User < ActiveRecord::Base
# Option 1: Purely overriding the #as_json method
def as_json(options={})
{ :name => self.name } # NOT including the email field
end
# Option 2: Working with the default #as_json method
def as_json(options={})
super(:only => [:name])
end
end
In our controller, we then just need to render JSON as normal (in the example below, it will just always return JSON, whether it’s an HTML request or not):
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
render :json => User.all
end
end
Note that you don’t need to call #to_json
yourself when using #render
… it will do it for you.
See the as_json documentation for details and more, like how to include associations.
Rendering Nothing or Errors
Sometimes you just want to send out an HTTP error code without any response body. The web is conflicted about the best practices for doing so (see This older blog for one approach or this SO answer for another set of answers) . Here’s a simple example (again we are just rendering the error in all cases):
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
render :nothing => true, :status => 404
end
end
Creating Dynamic Error Pages
You can create your own error pages. See this blog post.
Sometimes Heroku can require additional steps to properly display your error pages. See their error page docs here. You might need to delete the static pages in the app/public
directory first.
External Facing Security
Let’s say you want to only allow an API call if your user is logged in. Your existing controller authentication will work to cover this as well — just make sure you’ve got the right #before_action
set up (e.g. before_action :require_login
). This might be the case if both logged in and non-logged-in users will be viewing the page but each should see different data. You don’t want your not-logged-in-users to be able to make API requests for sensitive data just like you wouldn’t want them to be able to visit an unauthorized HTML page.
If you want to handle requests from an application that isn’t a web browser (e.g. the command line), you can’t rely on browser cookies to authenticate you. That’s why most APIs issue custom tokens to each authorized user which must be sent along with the request as part of the authentication process. We’ll talk a bit more about tokens in the next lesson.
Next Steps
Right now you’ve got the ability to use your Rails app to serve up not just HTML but also whatever formats you want. If you’d like to take this further and allow other developers to build on your platform (so they’ll be making programmatic requests instead of logging in as users), you’ll need to make your API system far more robust. We won’t cover it all here, but check out the following:
- Building Awesome Rails APIs has a lot of best practices for moving beyond a toy API and into a production-ready app.
Service Oriented Architecture (SOA)
This is a good time to introduce an architectural concept called “Service Oriented Architecture”. The basic idea is that your application will likely have many different services within it, for instance the payments processing, user registration, recommendation engine, etc. Instead of building all of these under the same master application, you break them out into fully independent pieces and have them talk to each other using internally facing APIs.
This is good for many reasons. Because each piece of your application doesn’t care how the other pieces work and it only knows how to ask for data via their APIs, it allows you to make major changes to the code within a service and the rest of your application works just the same. You can completely substitute one service for another and, as long as it communicates using the same API methods, it’s easy. You can use an external API for a part of your app (like payments) instead of an internal one. You can have a PHP app talking to a Python app talking to a Rails app and no one cares since they’re all communicating using APIs
It’s usually a good idea to strive to keep independent pieces of your application as independent as possible anyway. Formalizing this under the umbrella of SOA forces you to think in terms of exactly which methods you want to expose to the other parts of your application and it will make your code better along the way. An added benefit is that, when you assume that each major component of your application is independent, you can also isolate issues much easier and will be forced to handle errors in a reasonable way.
Using an SOA architecure for your whole application is sort of like breaking up a giant and complicated Ruby script into nice neat classes and methods, just on a broader scale.
One of the best known cases of switching to a service-oriented architecture was Amazon.com. Sometime in 2002, Jeff Bezos basically dictated that every group would switch to SOA or be fired. An infamous blog post from a Google Employee, accidentally released to the public instead of staying internal to the company, talked about Amazon’s strength with SOA. It’s a great read so check it out, but the basics of Bezos’ email are, as quoted from the post:
1) All teams will henceforth expose their data and functionality through service interfaces.
2) Teams must communicate with each other through these interfaces.
3) There will be no other form of interprocess communication allowed: no direct linking, no direct reads of another team’s data store, no shared-memory model, no back-doors whatsoever. The only communication allowed is via service interface calls over the network.
4) It doesn’t matter what technology they use. HTTP, Corba, Pubsub, custom protocols — doesn’t matter. Bezos doesn’t care.
5) All service interfaces, without exception, must be designed from the ground up to be externalizable. That is to say, the team must plan and design to be able to expose the interface to developers in the outside world. No exceptions.
6) Anyone who doesn’t do this will be fired.
SOA is a big deal. There are certainly a lot of issues that crop up when you’re using it — see this post on Amazon’s “lessons learned” — but it ultimately has a lot of benefit.
You probably won’t be worrying too much about SOA while building “toy” applications for yourself but it will certainly come up if you find yourself working at a tech company and it’s a good principle to become familiar with.
Your Assignment
- Read the Rails Guide on Controllers section 7 to learn about rendering JSON and XML.
- They are not required viewing (because they get a bit deeper than we’re scoped for), but if you’re interested, go check out the Railscasts in the Additional Resources section at the bottom of this lesson for more API goodness.
Conclusion
We’ll get more into using your application as an API during the course on Javascript. In that course, you’ll build some full stack apps that use Javascript AJAX calls to smooth out the user experience, which basically involves asking your Rails app for some XML or JSON data instead of a full HTML page. Then you’ll get to build some single page Javascript apps which rely on the API provided by your Rails app for all the necessary database data but otherwise completely run the show on the front end.
The best way to really figure out APIs is to build them and interface with them, so we’ll focus on that in the projects.
In the next lesson, we’ll cover working with other people’s APIs, which can add all kinds of firepower to your own application.
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
- Watch this free Railscast on making your App into an API
- Watch this free Railscast on securing your API
- Watch this free Railscast on versioning your API
- Building a public-facing API using view templates instead of
#to_json
to_json
oras_json
by Jonathan Julian gives specific examples of digging into theas_json
method.
Step 2:
Working With External APIs
Lots of the power of APIs comes from interfacing with third-party applications, which we’ll cover in this lesson.
Interfacing with APIs
Introduction
It’s pretty easy to turn your application into an API, but what about grabbing data from other APIs across the internet? That’s where things usually get a bit more challenging because they’re all different and you’ve got to authenticate yourself.
Most popular services offer APIs so developers can interface with them (they love it if you can get more people using their platform). Facebook, Twitter, Instagram, Flickr, Dropbox, AirBnB… They’ve all got APIs. Just Google “companyX API docs” and you’ll get to their developers section.
If you go to the documentation for an API, it can sometimes be a bit overwhelming because much of the material sort of assumes that you know what you’re doing, but some are definitely better than others. There are also elements that are common across almost all of them. The more you work with APIs (and get the hang of the authentication flow), the easier they get. You’ll be making mashups in no time.
This lesson will cover some general steps that are common across APIs and will do high level overviews of some of the methods for authenticating with APIs like Omniauth. Try to gain as much conceptual understanding as you can here and use the documentation each gem or API provides to help with the implementation. If you find great free learning resources that explain APIs, please let us know (try using the suggestion box at the bottom of the page)!
Points to Ponder
Look through these now and then use them to test yourself after doing the assignment
- What’s the best way to locate an API’s docs?
- What are the steps you’ll almost always have to go through when setting up your app to use an API?
- What is an API key?
- How is API use typically controlled?
- How do you avoid including an API’s secret token in your Github repo (e.g. hard coding it)?
- Why is it important to know which API version you’re using?
- What is a RESTful API and why does that make your life easier?
- What (basically) is OAuth?
- Why would a user prefer to sign into your site using Facebook instead of giving you a new password?
- How (basically) does this process work from the user’s perspective?
- How (basically) does this process work from your (the application developer’s) perspective?
- What are the basic rules of thumb for not abusing APIs?
- What is OmniAuth and why does it save you tons of time/pain?
- What is an SDK and why are they useful for working with APIs?
First Steps
You will need to register yourself and your application with the API provider. They will track and monitor your usage this way. Typically, there is a free tier of usage and it will cost you if you’re going over your limits, whether they are expressed in terms of total MB downloaded, number of requests, or number of transactions (for instance). Usually, even if you’re a user of their service, you will need to separately go to their developer portal.
You will need to get an API key from the API provider, which often is the last part of registration. This key will uniquely identify your application to the API provider and you will send it along with every request. It’s sort of like a user on your site automatically submitting their session cookie with each request so you know they’re logged in.
You’ll typically also get a “secret key” or similarly named code. Whereas the API key is usually public, the secret key is an added layer of security that’s required for the more secure APIs and you will use it to generate a cryptographic token that authenticates any requests you make. You will need to make sure you don’t include this secret key in your Git repo! Use the figaro
gem or environment variables to put the key on the server instead of hard coding it.
API Rates and Security Tokens
Most APIs require a different type of “security clearance” for different requests:
- You can usually make innocuous requests like asking for Tweets (with Twitter’s API of course) with straightforward and unauthenticated GET requests. You can make these from any command line or a browser tool like Chrome’s Rest Client. These types of API requests are usually severely rate limited to incentivize you to sign up.
- The next layer is making requests that include your API key. These are still usually fairly innocuous things (like getting public data) and limited by the API’s pricing tiers.
- More sensitive requests like asking for specific user data or submitting/modifying/deleting data will likely require you to use an authentication process involving your secret token. We’ll cover the basics of this in the project. Rates for these requests are subject to the API pricing tiers.
- Oftentimes, you actually want to make requests on behalf of a user. For instance, showing a user a dashboard of all his tweets and Facebook posts together would require asking Twitter for that user’s tweets and Facebook for that user’s posts. This can involve a LOT of requests over a large user base, but luckily you’re actually able to make them on the user’s behalf by asking for the user’s permission. We’ll cover this as well later, but basically you send the user to the API provider’s site to sign in, then the API provider will give you a user-specific token to use when making requests on their behalf in the future. Rates for this are usually more advantageous because they are covered in a per-user bucket. We typically use the OAuth protocol for this, as described below.
Versions
Tech companies, especially if they’ve been around for a while, typically have several versions of their API. Usually, they built a first draft version when they were a startup and then had to build a real one later, but still have to support the original since so many other applications are likely to be using it.
Just go for the latest version unless you have a compelling reason not to (it’s usually got a separate section of documentation for each version). Pay attention to which version’s docs you’re looking at… there’s nothing like the frustration of realizing you’ve been looking at the v1 API instead of the v2 API docs.
RESTful APIs
Just like your routes should ideally be set up in a RESTful way, so too should APIs. These days, most APIs are RESTful, meaning the usual batch of GET/PUT/PATCH/DELETE requests will retrieve resources as expected. The good part about setting up your application routes RESTfully is that your API will be the same way.
Working with RESTful APIs at least takes a lot of the headache out of the process since you can usually sort of guess what you should be doing, then can head over to the docs to figure out how exactly and what format you’ll get the results back in. For instance, just like you’d expect the GET request to the /users
route in your app to display a page listing all its users, a GET request to a RESTful API for the same route should probably give you back a JSON or XML object filled with all the users (or at least some paginated sample of them).
Oauth and Login via API
You’ve seen sites where their homepage lets you log in using Facebook or Twitter or LinkedIn. After logging in with one of those third-party services you magically have a new account with them but don’t need to give them a new password.
OAuth is usually behind this. It solves the very real problem of user data privacy and access control. The idea is that the user shouldn’t need to give your awesome application their password in order for you to make requests on their behalf. So OAuth allows Facebook to act as a sort of intermediary when dealing with the user.
This has two great use cases — logging in the user with an external site like Facebook and making requests for or submissions of data on the User’s behalf.
In the first case, you never actually discover the user’s Facebook password. They get redirected to Facebook’s website to sign in, where they authorize you to use some of their data (which you’ll have to configure when you set up this process). Facebook then calls you back (by sending a request to a URL of your choosing with the proper data) and gives you a special access token for that user. You can then use that to get any additional data that the user has authorized you to access (like their name and email address). Now you can create a new user in your database with that data and everyone’s relatively happy.
From the user’s perspective, they only need to remember their Facebook password to log into your site so it’s easy for them. They also don’t need to trust you with their password. As long as they trust Facebook, they can use your site. Also, if your site is doing bad things with their data (like when SocialCam spammed the hell out of everyone’s Facebook timeline for a while), they can tell Facebook to stop allowing you to use their data and Facebook will turn off access for the token they gave you.
From Facebook’s perspective, they retain majority ownership of the user and nestle deeper into everyone’s lives (for better or for worse).
Once you have the user token, you are allowed to make requests or submissions based on whatever permissions Facebook (and the user) authorized you to. That could involve asking who their friends are, posting on their timeline, or “liking” something. You just need to include the token as a part of your authentication process for the request.
Restrictions
Every site, in addition to rate limiting their API, will have terms of use. This usually covers what you’re allowed to do with the data you gather. For instance, they probably aren’t going to allow you to store a whole bunch of their data in your own database (harvesting). They also probably won’t allow you to do anything SPAMmy or which will hurt their user’s experience. Common sense should be your initial guide, but consult the TOU documentation for specifics. Basically, if you’ll be hurting their user’s experience or taking their precious data, you can’t do it.
It should be noted that any time you develop using someone else’s API, you’re putting yourself at their mercy. If you’re using it to the point where you pay for data, they’ll love you. If you get too successful and become competitive with them, they’ve got you by the neck and will cut you off or demand exorbitant fees. Just be cognizant of those risks.
OAuth 2.0 Basics
OAuth 2.0 is actually pretty complicated, so I’ll just cover the basic process. You don’t really need to care how exactly it works behind the scenes until you start really developing with it or trying to create your own API that uses it. You will need to understand the steps involved in the user experience because, well, the user is the reason you’re building your application.
Basically (still using Facebook as an example):
- User tries to access a page on your app and you ask the user to login
- User chooses the “Login With Facebook” option
- User is redirected to a Facebook page asking them to review the permissions you are asking for and telling them to sign in. The URI will contain parameters that tell Facebook who your application is and possibly which URI they should submit their response to (or maybe you specified this as a part of your API registration process with them).
- User decides you seem like a fun application so he’ll allow you to see his email address and post to his timeline. He signs in to his Facebook account. Facebook creates an authorization code and sends it back to your application’s callback URI.
- The user waits while your application takes that authorization code and uses it to ask Facebook for the real good stuff. Facebook makes sure your application is the same one the user authorized, then POSTs back to you a unique authentication token for the user (which likely expires in 90 days) and any data you asked for up front (like email address).
- You store the user’s unique token in your database and use it, along with your application key(s), to make any subsequent requests on the user’s behalf.
See this brief overview of OAuth 2.0 for an overview. Then check out this more substantive explanation from tutsplus.com.
Implementing OAuth 2.0 in Rails — Use Omniauth!
This sounds horribly complicated! Someone must have made a gem for it…
Luckily someone has. Many someones, actually. There is a generic OAuth gem called omniauth
(docs available on Github) and then a separate gem which provides a specific authentication strategy for every major API (see the list HERE). Once you’ve gone through things with one of them, you’ll become comfortable with all of them.
I’ll leave it to the projects to walk through using Omniauth since it’s much easier to learn by doing than reading a bunch of bullet points.
SDKs
In addition to or instead of API access, many companies provide SDKs (software development kits). Usually these are Javascript libraries that contain all the code necessary to access their API. This can be useful because you’re then able to access the API with simple Javascript methods instead of doing backflips on your own backend. It comes with the downside, however, of expanding your code base and forcing you to use their conventions for everything.
We won’t cover SDKs explicitly in this course but they should be well within reach to pick up by reading the documentation.
Your Assignment
- Watch this Railscast on using Omniauth to allow Twitter Signin.
- Read through the Omniauth documentation
- Pick an API that you really might like to interface with or a web product you use almost every day (e.g. Google, Facebook, Instagram…). Google for its docs, e.g. with “instagram api documentation”, and have a look at them. Some docs are better than others, but they will be your source for understanding which methods you can call, what they will return, how to register your application to get an API key, and more useful tidbits.
Conclusion
APIs are fundamental to making rich web applications and they’re also a lot of fun — it makes your app feel a lot more “real” when you’re able to let your users log in using Facebook or if you can display information from different sources across the web. If you’re building a startup, it improves the user experience enough that you’ll likely see an uptick in conversion rates.
Working with external APIs can be incredibly rewarding because you’re able to leverage functionality that others have spent a lot of time perfecting but also incredibly frustrating because they’re all different and you have to rely on gems which are doing things behind the scenes that you’re not entirely sure of. Over time, you’ll start to see a lot of similarities between APIs and the procedure for working with them will feel more and more comfortable. To help get you there, the next project will have you working with an API and your final project will have you implementing signin via API as well.
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
- See This SO Post on interfacing with third-party APIs for tips.
Project:
APIs
In this project, you’ll both build your own API and work with a third-party API.
Projects: Building and Using APIs
Don’t forget to use Git to save your projects!
Warmup: Exploring the Flickr API
In this warmup, you’ll get a chance to poke around with an existing API from Flickr. You’ll need to read the documentation to understand which calls to make but they have a nice API explorer tool which submits API calls on your behalf.
Your Task
- Head over to the Flickr API Documentation Page. You can just google
XYZ API docs
to locate these pages, which is usually much faster and easier than trying to find them by navigating the websites themselves. - Look around at the different methods available. They have a couple of different request formats, but check out the RESTful API format by clicking on the link on the left under “Request Formats” called Rest.
- This shows you the format that a typical API call would take — you will make your request to the endpoint at
http://api.flickr.com/services/rest/
and include any required data in the GET query string or the POST body. - Look around at the various methods. How would you upload a photo? How about getting your contacts list? Lots of these methods will require you to authenticate your application or user account first.
- Check out the Search method docs. This request doesn’t require you to authenticate, just provide an API key (which you would get by registering as a developer on their platform). Browse through all the arguments that can be used.
- If you go to the bottom of the Search docs, you’ll see a link to the Search API Explorer. This tool lets you actually execute requests using Flickr’s API key for illustrative purposes. You just enter the options you want and it will make the request for you. Try entering “puppies” under the “tags” argument, then scroll to the bottom. Change the response “Output” dropdown to JSON then click “Call Method”.
- When the page refreshes, you’ll see your results down at the bottom. You should see a big list of photo objects (after some meta data) that were returned by your search. They look like:
{ "id": "11357337313", "owner": "84645040@N00", "secret": "6dd795c9c6", "server": "3805", "farm": 4, "title": "Gavin-Feb2013-0127", "ispublic": 1, "isfriend": 0, "isfamily": 0 },
More interestingly, you can see the URL they used to make the request below that. I’ve broken it apart here to show the parameters more clearly:
http://api.flickr.com/services/rest/ ?method=flickr.photos.search &api_key=e0eb58bf4b3e29b253e86d6092e69dee &tags=puppies &format=json &nojsoncallback=1 &api_sig=200efb63cb01a3d141fff12585e1e20a
- The URL contains the REST endpoint we looked at before, along with our search query and some other options like the API key and format. If you copy and paste that into your browser, you’ll see the same batch of output.
- If you look back on the main API docs page in the “Read these first” box, there’s a link that says URLs. Follow that link.
- Flickr’s API requires two steps to actually display a photo — you need to get a photo’s meta information (which we just received in our search results) and then you need to piece it together into a URL that Flickr can understand to actually retrieve the photo. The format they suggest is:
http://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}.jpg
We can plug in values from the previously retrieved photo to display a photo:
http://farm4.staticflickr.com/3805/11357337313_6dd795c9c6.jpg
Which looks a lot like:
We could also add in additional parameters like
size
on the end. - Tada! Every API is different and you’ve got to read through their documentation to understand the basic format of using it. Sometimes it can be helpful to search for a YouTube or NetTuts video with a quick overview as well.
Project 1: Building a Simple Kittens API
This is a fast and straightforward project where you’ll set up a Rails app to be a data-producing API… which is just a fancy way of saying that all your controller methods will render data instead of HTML. Consider this a drill in quickly building a pure vanilla RESTful resource. We won’t be working with an external API until the second project.
Your Task
HTML
We’ll start by building our Kitten application to work normally in the browser with HTML.
- Set up a new Rails application (
odin-kittens
) and Git repo - Update the README to describe the application and link back to this project.
- Build a Kitten model with attributes of
:name
,:age
,:cuteness
, and:softness
. - Build a KittensController and
:kittens
routes for all 7 RESTful actions. - Set your default route to
KittensController#index
- Fill out each of your controller actions and their corresponding views to display a very basic HTML page —
#index
should just list all Kittens,#show
should display a single Kitten,#new
should render a simple Kitten creation form,#edit
should use the same form (which should be a partial used by both the New and Edit views) to Edit the Kitten,#create
and#update
should do their jobs. - Make a
delete
link on the Kitten’s Show and Edit pages, as well as next to each Kitten listed in the Index page. - Implement a simple display of the
flash
hash (like you did in the tutorial) which congratulates you on adding or editing or deleting kittens and makes fun of you for errors in your form. - Test out your Kitten creation machine to make sure all your controller actions are running properly.
JSON API
Now it’s time to make the Kittens resource available via API.
- Open a new command line tab and fire up IRB.
> require 'rest_client'
(you may need to$ gem install rest_client
if you haven’t already). Test it out by making a request to your application using> response = RestClient.get("http://localhost:3000/kittens")
- You should get a sloppy mess of HTML. If you check out your server output, it’s probably processing as XML, e.g.
Processing by KittensController#index as XML
- Try asking specifically for a JSON response by adding the option
:accept => :json
, e.g.RestClient.get("http://localhost:3000/kittens", :accept => :json)
. It should throw an error. - Now modify your KittenController’s
#index
method to#respond_to
JSON and render the proper variables. - Test it out by making sure your RestClient calls return the proper JSON strings.
- Do the same for your
#show
method, which will require you to provide an ID when making your request. Your CSRF protection will prevent you from creating, updating or deleting kittens via the API, so it’s not necessary to implement those.
This project may seem simple, but now you’ve got a website that is both a normal HTML-producing back end AND an API that can be used to pull data from it. You could use Javascript calls from the front end to dynamically refresh your data now or even to load the whole page in the first place. Or maybe you’ll be hooking up a Kittens app to your iPhone and need a back end. It doesn’t matter, since now you’ve got a RESTful API.
Student Solutions
Send us your solution so we can show others! Submit a link to the Github repo with your files in it here using any of the methods listed on the contributing page. Please include your partner’s github handle somewhere in the description if they would like attribution.
- sirramongabriel’s solution
- jamie’s solution
- Donald’s solution
- Adrian Badarau’s solution
- Marina Sergeyeva’s solution
- Kate McFaul’s solution
- Vidul’s solution
- Jason Matthews’ solution
- Dominik Stodolny’s solution
- Kevin Mulhern’s solution
- AtActionParks’s solution
- Hutton Brandon’s solution
- Jeremy Mauzy’s solution
- dchen71’s solution
- Matias Pan’s solution
- Add your solution above this line!
Project 2: Using a Third Party API
Remember way back in the warm-up when you played with the Flickr API? Now it’s time for you to actually use it. Huzzah! You’ll create a simple photo widget that allows you to display photos from your Flickr feed (or someone else’s). We’ll rely on a tutorial for much of the heavy lifting but the principles of what you do here will be repeatable for use with other APIs.
Your Task
- Go back to the Flickr API Docs and click Create an App at the top.
- Follow the steps for getting your API key. You’ll have to sign in or sign up for Yahoo (someone has to these days) and give them some basic information about your app. Select “Apply for a non-commercial key” and let them know how awesome your photo feed app will be. You’ll automatically get a key generated for you, in addition to a secret key. Copy both of these somewhere you can get to them later.
- Use the idGettr website to look up your ID by pasting in your flickr username in the example URL, e.g.
http://www.flickr.com/photos/eriktrautman/
. You’ll need that later for some of the API methods. - Upload a few photos to your photostream!
- Follow the tutorial listed at pixellatedvisions.com for building a Flickr sidebar. You’ve already completed a couple of the steps. The tutorial is old but should still work for you. It uses the
flickr_fu
gem, which no longer works with the Flickr API, but there are other options out there (like Flickraw). You’ll find a gem for pretty much every API out there. They will all require you to include your API keys and secret keys somehow, in this case by using theconfig/flickr.yml
file. - One note is that it’s not good practice to have your secret key hard coded into your app because then it’s hardly a secret, especially if you’re pushing to Github. A better practice is to store the key in an environment variable instead and/or use a gem like
figaro
(see docs). Environment variables allow you to push your key to your app directly from the command line when it fires up. Figaro operates under the same principle, though it helps you out by allowing you to store the keys in an actual file that just doesn’t get committed with the rest of your code. Use one of these techniques unless you’re a cowboy. They are well described in Daniel Kehoe’s RailsApps article. - Build a simple StaticPagesController to display a home page with a simple form. The form should just be a single text field which takes the ID for a Flickr user. Once the form is submitted, the page should refresh and display the photos from that user.
- Modify the image feed from the tutorial’s sidebar to display in the main page body instead. This is to test how much you learned vs. copy-pasted!
- Ask for your friends’ flickr IDs or find random photofeeds on the web. View them in your app and react appropriately.
Student Solutions
Send us your solution so we can show others! Submit a link to the Github repo with your files in it here using any of the methods listed on the contributing page. Please include your partner’s github handle somewhere in the description if they would like attribution.
- Donald’s solution
- Adrian Badarau’s solution
- Jack’s solution
- Dominik Stodolny’s solution
- Alex’s solution | View in browser
- Kevin Mulhern’s solution
- AtActionPark’s solution – With fix for ssl error on windows
- Jeremy Mauzy’s solution
- Add your solution above this line!
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something *
Step 3:
Mailers
You don’t often think about where your email comes from. Here you’ll learn how to send it from your app.
Mailers
Introduction
Email is underappreciated in its complexity on many levels. I certainly didn’t think about it much until I needed to actually bake it into my apps. But what goes on behind the scenes, especially after hitting “send”, is pretty impressive… lots of bouncing around the architecture of the internet, bypassing firewalls, and navigating SPAM filters. Luckily all this can be handled by some specialty Heroku add-ons or other third parties.
The actual production of the email is what we’ll cover here… i.e. how do you make that special “thanks for signing up, userX” email. Creating and sending email is actually conceptually similar to rendering views and shipping them to the web browser, at least from your point of view as a Rails dev. In this lesson we’ll cover that process and you’ll get a chance to send your own emails in the projects.
Points to Ponder
Look through these now and then use them to test yourself after doing the assignment
- What is a mailer?
- How do you set up a new mailer from the command line?
- How are mailers similar to controllers? To models?
- How do you pass instance variables from the mailer to the mailer view?
- Why do you need both a text and HTML version of your mails?
- How do you send an email directly from the Rails console?
- How can you take advantage of add-ons and third-party programs to send email?
- What is the
letter_opener
gem good for? - Why can’t you use
*_path
link helpers in mailer views? - How do you style up a pretty looking HTML email?
Brief Overview
To send email, Rails uses the ActionMailer
gem (one of the 7 core gems that make it up). A mailer acts similar to a model and controller baked into one. You will create a new mailer just like you would with a new controller ($ rails generate mailer SomeName
). You’ll then set up methods for each email that you might want it to send (e.g. welcome email, followup email, thanks for purchasing email…). Sounds a lot like controller actions, eh?
In each method, you need to identify the key fields and any variables that will be used in the text of the email (like the user’s name). The actual email itself is just a view. They live in the app/views
folder along with the rest of them, though in a sub-folder named after the mailer.
One distinction between mailer views and “normal” views is that emails typically have two separate formats — HTML and text. Most people will view the HTML version but some will have HTML disabled and so they will need the text version in order to see your email. Having the two versions also helps you bypass SPAM filters. You’ll quickly find that many things you do regarding email have to do with getting past the dreaded SPAM filter.
So you set up one view called, for instance, app/views/user_mailer/welcome_email.html.erb
and another called app/views/user_mailer/welcome_email.text.erb
. It is kind of annoying having to manage two different versions of the same email but such is the cost of accessibility and SPAM fighting. Another thing you’ll notice is that you can use ERB (or HAML etc) preprocessing on your emails too. Just like any other view, it allows you to dynamically create content that includes things like your user’s name or non-sensitive account information. This is all based on which variables you pass the view from your mailer, just like passing a controller action’s instance variables to a normal view.
Mailers are actually a two-step process — first you build the email itself and then you call the #deliver
(or #deliver!
) method to actually send it. One way that mailers are different from controllers is that you call them directly instead of working through the router. When you want to call the welcome email, you will write UserMailer.welcome_email(@user)
, which returns the email object. Deliver it by calling the #deliver
method on that object, for a total chain of: UserMailer.welcome_email(@user).deliver
.
As long as your view files (the HTML and text) are named the same as your mailer methods, Rails will find everything okay and will send the email (with both the HTML and text parts) using whichever addon you’ve chosen to use for sending it. The Rails Guide reading does a good job walking through the process, so you’ll get a chance to see it in action there.
Callbacks
Mailers allow you to use callbacks just like a normal controller, for instance the after_action
callback. They will run after the email is generated, not after it is sent, so you’ll be able to modify parts of the email if you need to. You get access to the instance variables of the mail instance, so you can use the @user
variable as a part of your logic.
Email Addons
In the reading you’ll see how to send mail using your Gmail account, but if you’re building a real application you’ll obviously want something a bit more robust. There are several leading players in the space of sending your email for you. Their whole job is to handle getting your mail delivered and opened so you can focus on building your application. They are usually available as add-ons to Heroku (like New Relic was, which we saw in the lesson on deployment), so all you need to do is properly configure them.
SendGrid is the add-on used with this website for delivering welcome emails and the like and it’s pretty straightforward. See the documentation here, which includes instructions for how you should set up your config/environment.rb
file to get ActionMailer to interface with them. You will need to use environment variables (or the figaro
gem) again to avoid hard coding your password and username.
Pricing for this, as most things, is free up until a certain usage tier. While you’re building toy apps, it will do just fine. Other options out there include MailGun and PostMark, all available in the email section of the Heroku Addon Store.
You’ll get a chance to play with mailers and addons in the projects.
Letter Opener
One key thing to note is that you don’t want to fire off a bunch of emails when you’re testing your app in the development environment. That’s not just bad practice, it can make your users pretty unhappy and get you put on SPAM lists. No bueno. But you do want to make sure the email function is working properly. Luckily, there’s a simple solution which is quite useful.
The Letter Opener gem (see docs), put in your development
group of the Gemfile, will take your emails and display them in the web browser for you whenever they would otherwise be sent. You just switch a config setting in your config/environments/development.rb
file and you’re good to go. Sweet.
Email Wisdom
- Email is SLOW! It can take 1-2 seconds per email to send, so don’t make your main application do it when you’re serving a whole bunch of them because then anyone trying to access it will be shut out.
- Make sure you use full URLs in any links in your mailer (so
_url
not_path
helper methods), since the user will be opening the email and clicking the link at an external source. In yourconfig/environments/production.rb
file you’ll want to make sure to specify your website’s host name using something likeconfig.action_mailer.default_url_options = { :host => 'yourapp.com' }
. If it’s not set, you may get an error message about your host or your links may look funny. - The
#deliver!
method will throw an error on delivery failure whereas#deliver
will return false (failing silently). - When styling your email HTML, you won’t have access to any stylesheets so you’ll need to do all the styling either inline or using
<style>
tags. - Attaching images to emails (like using logos in the HTML version) can be a bit of a pain. See the reading.
Your Assignment
- Read the Rails Guide on ActionMailer chapters 1 and 2.
- Skim the brief chapter 3 on receiving emails. You’ll be able to refer back to it if you need to.
- Read chapter 4 and 5 to learn about callbacks and helpers.
- Read chapter 6, which covers sending mail with your Gmail.
- Skim chapters 7-8 on testing and intercepting emails.
Conclusion
Sending email is just a slightly different way of using the same patterns you’ve already been using for controllers and views, so it should be pretty straightforward to pick up. You’ll have to navigate the usual batch of errors when trying out new things (often related to the configuration or naming your files properly), but it’ll come to you quickly.
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
Project:
Sending Confirmation Emails
Add email functionality to an existing project. Just don’t SPAM, it’s frowned upon.
Project: Ruby on Rails Mailers
Don’t forget to use Git to save your projects!
Project: Sending Welcome Emails
Setting up a mailer is a relatively straightforward task. It’s very similar to building a new controller and views. Once you’ve made a couple, it should come naturally.
Your Task
You’ll be dusting off your Flight Booker project (or one of the other projects that has users registering) and having it send out a “You have booked your ticket” email to all Passengers when they are created as part of the booking process.
- Locate and load up the project file.
- Do some pushups and jumping jacks. You’ve been spending a bit too much time at the computer lately.
- Generate your new mailer with
$ rails generate mailer PassengerMailer
- Install the
letter_opener
gem (see docs here) to open your emails in the browser instead of sending them in the development environment. - Follow through the steps listed in the Rails Guide to create the action to send the “thank you” email.
- Build both a
.html.erb
and.text.erb
version of your thank you ticket email. - Test that the email sends by creating a new flight booking (
letter_opener
should open it in the browser for you if you’ve set it up properly) - Try out one other trick — call the mailer directly from the Rails Console using something like
> PassengerMailer.thank_you_email(Passenger.first).deliver!
. - Extra Credit: Deploy it to Heroku and try it out. If you deploy to Heroku, there will be a bit of additional setup to get the SendGrid add-on (see docs) and make sure your configuration is set up properly. The docs describe how to get that up and going.
Student Solutions
Send us your solution so we can show others! Submit a link to the Github repo with your files in it here using any of the methods listed on the contributing page. Please include your partner’s github handle somewhere in the description if they would like attribution.
- jamie’s solution | View in browser
- Donald’s solution | View in browser
- Marina Sergeyeva’s solution | View in browser
- Aleksandar’s solution
- Dominik Stodolny’s solution
- Kevin Mulhern’s solution | View in browser
- AtActionPark’s solution
- Andrej Dragojevic’s solution | View in browser
- dchen71’s solution | View in browser
- Matias Pan’s solution
- Add your solution above this line!
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
Step 4:
Advanced Topics
A mash-up of orphan topics like advanced routing, layouts, metaprogramming and design patterns.
Advanced Topics
Introduction
There are some topics that we just haven’t had a chance to get into yet but will prove useful for you to know. In this section we’ll cover advanced routing, layouts, and a brief introduction to metaprogramming.
Points to Ponder
Look through these now and then use them to test yourself after doing the assignment
- When do you need to use a singular Resource vs a plural Resources in your router?
- What is the “missing” route when using a singular Resource? (there are only 6 when you
$ rake routes
) What else is missing from many of the other routes? - Why would you use nested routes?
- What order do you specify their respective IDs? What are they called in
params
? - Why might you use a “member” route?
- How are “member” and “collection” routes incredibly similar? Slightly different?
- How do you set up a redirect route that also passes along any parameters?
- How do you name a route using an alias?
- Why might you want to use nested or multiple layouts?
- How would you (roughly) go about implementing this?
- How can you pass variables between your layouts?
- How do you
#yield
to#content_for
content? - What is metaprogramming?
- How do you use the
#send
method to run a method? - How do you create a new method on the fly?
- When does Ruby call the
#method_missing
method? - How can you use
#method_missing
to your advantage? - What are Design Patterns?
- What are the SOLID principles?
Advanced Routing
You should be quite familiar by now with the bread and butter of routing — converting RESTful requests using the familiar HTTP verbs into mappings for specific controller actions (whether using the #resources
method or explicitly specifying them using the get
method. That’s 90% of what you’ll use your routes file for… but that other 10% gives you some pretty neat options like redirecting directly from the routes file, nesting routes inside each other, or parsing parameters from the incoming request.
Singular Resources
You might have already run into this at some point without necessarily understanding it. Up until now, we’ve been talking about resources (like “posts” and “users”) where there are a whole lot of them. It seems fairly intuitive. In your config/routes.rb
file, you represent these simply with a single line like resources :users
.
Sometimes there are also resources where it actually only makes sense for there to be one. An example would be a User dashboard which displays interesting facts based on whichever user is logged in. There is only one dashboard template, it just happens to be smart enough to display things that are relevant for the user who is currently logged in.
In this case, it doesn’t make a whole lot of sense to display an “index” of dashboards, since there is only one (it just changes based on who is logged in). We can also say that, for any of the other actions which would normally require an ID to differentiate which resource we’re operating on (like #show
), since there’s only one, we no longer need the id
parameter.
The routes file line for a singular resource would look like:
# in config/routes.rb
resource :dashboard
Just note that the word “resource” is singular and so is dashboard
. That trips up a lot of people who make the typo of writing “resource” instead of “resources” when they really want plural resources (which are more common).
The $ rake routes
for a singular resource would only contain 6 routes (since we don’t use #index
anymore), and you would no longer see any of the :id
portions of the routes, e.g.
new_dashboard GET /dashboard/new(.:format) dashboards#new
…compared with the plural version of the same route:
new_post GET /posts/:id/new(.:format) posts#new
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something about Singular Resources
Nested Routes
Sometimes it just makes sense for one resource to be nested inside of another. For instance, a listing of lessons like this logically falls within a listing of courses — so you’d expect a URL sort of like http://example.com/courses/1/lessons/3
. The way to achieve this nesting is in the routes file by literally nesting one resource inside a block given to another, which might look something like:
# config/routes.rb
TestApp::Application.routes.draw do
resources :courses do
resources :lessons
end
end
Note that the #resources
method now takes a block which will consist of a set of routes.
When you visit the URL, you’ll have to specify the :id
parameter for BOTH objects. The $ rake routes
for the above would include something like:
course_lesson GET /courses/:course_id/lessons/:id(.:format) lessons#show
It should also be noted that you’re being taken to the controller of the deepest nested resource, and that’s also the :id
parameter which will be called simply :id
(any parent resource parameters, as in the above, will be specifically called something like :course_id
).
View helpers are also automatically generated in a logical way (as you can see in your $ rake routes
output). When you use view helpers like #course_lesson_path
you will need to specify both parameters in order, e.g. course_lesson_path(1,3)
.
Don’t nest routes too deeply! If you’re more than a layer or two deep, something should be different. In fact, oftentimes you’ll see only some of the controller actions nested — only the ones that actually need the parent’s ID to uniquely specify it. For instance, you can grab a specific Lesson by knowing only its ID. But to get all the lessons that are listed beneath a specific Course, you need the Course ID so it will have to be nested. Same is true for creating lessons, since they will need a parent specified:
# config/routes.rb
TestApp::Application.routes.draw do
resources :courses do
resources :lessons, :only => [:index, :create]
end
end
If this seems a bit confusing at first, you’ll pick it up quickly when you actually run into it in your own coding. If you find yourself working inside your controller and needing the parent’s ID, the route should have been nested. If you find that you don’t need the parent’s ID, it doesn’t need to be nested. Easy enough.
Member and Collection Routes
Sometimes you want to add another non-RESTful route to a resource. If you’d like to add a route to just a single member of that resource, use the #member
method:
# config/routes.rb
TestApp::Application.routes.draw do
resources :courses do
member do
get "preview" # Preview a single course
end
end
end
That route would map to the courses#preview
action. You can add as many as you’d like.
If you’d like to add a non-RESTful route to the whole collection of your resource (so you don’t need to specify the :id
attribute, like with the index
action), you instead use the #collection
method:
# config/routes.rb
TestApp::Application.routes.draw do
resources :courses do
member do
get "preview" # Preview a single course (requires ID)
end
collection do
get "upcoming" # Show a list of *all* upcoming courses (no ID needed)
end
end
end
The upcoming
route will map to the courses#upcoming
action but will not take an :id
parameter.
If any of this seems confusing, just play around with them and run $ rake routes
to see what is happening behind the scenes.
Redirects and Wildcard Routes
You might want to provide a URL out of convenience for your user but map it directly to another one you’re already using. Use a redirect:
# config/routes.rb
TestApp::Application.routes.draw do
get 'courses/:course_name' => redirect('/courses/%{course_name}/lessons'), :as => "course"
end
Well, that got interesting fast. The basic principle here is to just use the #redirect
method to send one route to another route. If your route is quite simple, it’s a really straightforward method. But if you want to also send the original parameters, you need to do a bit of gymnastics by capturing the parameter inside %{here}
. Note the single quotes around everything.
In the example above, we’ve also renamed the route for convenience by using an alias with the :as
parameter. This lets us use that name in methods like the #_path
helpers. Again, test out your $ rake routes
with questions.
Advanced Layouts: Nesting Layouts and Passing Information
We got pretty good coverage of view layouts in the lesson on Views but one other topic involves rendering multiple layouts for one page, which allows you to create unique sections that still reuse a lot of the stylings that you might want to keep consistent across your whole site (e.g. the footer). For example, maybe the user pages should have a different styling than your home page. The first thought might be to try and have a different stylesheet for each layout but remember that Rails’ Asset Pipeline jams all your stylesheets together anyway.
A better way of doing things is to tell your layout to do some stuff (whatever you might normally have your layout do) and then render another layout using the render :template => "your_layout.html.erb"
method. You are sort of using your layouts like a view might use a view partial.
You can also pass information from the first layout to the one it renders by using the #content_for
method. This lets you create logic in your main layout that is dependent on what is passed by your individual layout files… the possibilities are endless.
For instance, you might have a specific layout file for your static pages called app/views/layouts/static_pages.html.erb
. This file will be rendered by default (if it exists) for views generated from your StaticPagesController (which is a Rails default). Let’s say, though, that you want your static pages to look almost identical to the rest of the site but you don’t want the navbar to appear across the top.
In this case, you would tell your static_pages.html.erb
layout to call the application.html.erb
layout but also pass it some special CSS by using the #content_for
method, e.g.
# app/views/layouts/static_pages.html.erb
<% content_for :stylesheets do %>
#navbar {display: none}
<% end %>
<%= render :template => "layouts/application" %>
Then your application.html.erb
layout needs to be set up to catch that content and use it, for instance by adding this #yield
line:
# app/views/layouts/application.html.erb
...
<head>
...
<style><%= yield :stylesheets %></style>
</head>
...
render :template => "static_pages.html.erb"
...
When you #yield
to a particular content block, in this case :stylesheets
, it will essentially drop the code from inside of that content_for
‘s block to where the #yield
method was. So in the above example, we effectively added some CSS styling to the application layout by first rendering a special static_pages.html.erb
layout and then passing the styles to the main application.html.erb
layout using #content_for
. The result would look like:
# app/views/layouts/application.html.erb
...
<head>
...
<style> #navbar {display: none} </style>
</head>
...
This trick is useful for more than just passing stylesheet information… any time you find yourself wanting to make a section of your site look different but without totally redesigning it with a fully new layout, you might consider nesting your layouts and passing information from one to another.
Metaprogramming Rails
What is “Metaprogramming”? It’s a great and useful concept that’s used all over Rails and you can put it to work yourself too. It’s basically the idea that your application or script actually creates functions or methods or classes on the fly while it’s running and can dynamically call them as well. It’s one of the great parts of using an interpreted language like Ruby… it’s sort of baked into the language. We’ll just skim the surface here but you should definitely look into it more on your own once you feel comfortable with the nuts and bolts of Rails.
An example of metaprogramming in action in Rails is with the route helpers. When your Rails application fires up for the first time, it loads the config/routes.rb
file, which might contain the line get "home" => "static_pages#home"
so your users can type http://www.yoursite.com/home
to get back to the home page. Rails then creates a couple method for you, including the home_path
and home_url
helpers. That’s one part of metaprogramming!
The routes example almost isn’t fair, though, because you wrote your routes.rb
file and probably hard coded a bunch of #home_path
or #home_url
method calls based on what you knew would be in there. What about more dynamic situations where you don’t know ahead of time what the method is going to be called?
Ruby provides the #send
method to save the day. If you want to run a method on an object, just send that object the method and any arguments you want. A simple example you can do on your command line is 1+2
:
> 1 + 2
=> 3
> 1.send(:+, 2)
=> 3
In an ordinary situation, there’s no reason to use the #send
method but if you don’t know which method you’re going to need to call, it’s a lifesaver. Just pass it the symbolized name of the method you want to run on that object and Ruby will go looking for it.
But how do you define a new method on the fly anyway? In this case, you can use the #define_method
method, which takes the symbol of what you’d like to define and a block representing the method itself. The following examples were taken from this metaprogramming guide from ruby-metaprogramming.rubylearning.com:
class Rubyist
define_method :hello do |my_arg|
my_arg
end
end
obj = Rubyist.new
puts(obj.hello('Matz')) # => Matz
Another very powerful tool is the #method_missing
method. You’ve certainly seen errors that say something to the effect of “Hey you, you tried to call a method that doesn’t exist!” and the stack trace will probably run through something called method_missing
. Most likely, you had a typo and spelled your method incorrectly.
Basically, #method_missing
is a method of Ruby’s BasicObject
class which gets inherited by every single object in Ruby and it is called whenever you try to run a method that doesn’t actually exist. It also gets passed all the arguments you tried to send and any blocks that went with it. That means that you can override #method_missing
yourself for a given object and use whatever was previously called, for example printing out a message saying the name of the method you tried to call and its arguments:
class Rubyist
def method_missing(m, *args, &block)
str = "Called #{m} with #{args.inspect}"
if block_given?
puts str + " and also a block: #{block}"
else
puts str
end
end
end
> Rubyist.new.anything
Called anything with []
=> nil
> Rubyist.new.anything(3, 4) { "something" }
Called anything with [3, 4] and also a block: #<Proc:0x007fa0261d2ae0@(irb):38>
=> nil
Metaprogramming is really nifty stuff and there are tons of interesting uses for it. You don’t need to master it to learn Rails, so only dive into it once you’re comfortable with Rails, but it will certainly be useful to you in the real world. There are all kinds of metaprogramming tricks and patterns and tips out there but it’s beyond the scope of this course to dive into them.
Here’s a good example of simple metaprogramming to DRY up your code.
Check out Metaprogramming Ruby by Paolo Perrotta if you’re really curious.
Design Patterns
Design patterns have a mixed reputation among software developers. On the one hand, they represent “best practices” for how to code past a given situation (not specific code, just a template for how to fix something). On the other, they can be sort of needlessly prescriptive. See the Wikipedia article on Design Patterns for an overview. We won’t be covering specific patterns in this course.
The Wikipedia article on SOLID provides a good overview and good links related to SOLID software design. If you’re looking to write great code, you’ll need to know each of the principles the letters represent (paraphrasing):
- Single Responsibility Principle (A class should only have a single responsibility)
- Open/Closed Principle (your code entities should be open for extension but closed to modification)
- Liskov Substitution Principle (replacing an object with one of its sub-types shouldn’t break anything)
- Interface Segregation Principle (writing many client-specific interfaces is better than one behemoth general-use interface… think APIs)
- Dependency Inversion Principle (instead of high level constructs depending on lower level ones, make them rely on abstractions instead)
Luckily, Rails has done a pretty good job of following these, so you should have absorbed some good habits just through using it. But you’ll want to take a minute and read up on each of them (including the odd-sounding ones) because they’re fairly central to all software engineering (and a ripe interview question).
If you’re particularly interested in pursuing design patterns, check out the “Gang of Four” (GoF) Patterns laid out in this blog post from blackwasp.co.uk.
There’s a useful book written on anti-patterns, which can help you clean up your code by identifying bad smells, called Rails Antipatterns by Tammer Saleh and Chad Pytel.
I18n: Internationalization
Internationalization and Localization is the process of adapting your application to fit specific geographies and/or languages. It’s outside our scope to cover, but for those who are interested, check out this Sitepoint tutorial on it, as suggested by K. Bates.
Your Assignment
- Skim the Rails Guide on Routing section 2.6 about namespacing.
- Read the same guide sections 2.7-3.7 to learn about nested, member and collection routes and more.
- Read the same guide, sections 3.8-3.15 for a variety of different advanced routing topics including constraining the inputs to your routes and redirection.
- Skim the same guide, chapter 4. Some stuff we’ve seen but most is just to give you a sense for what’s possible. When you need it, you’ll probably Google your way back there.
- Read the Rails Guide on Layouts section 3.5 to see how to pass information between your view file and your layout file, including CSS styles. Really take a minute to understand what’s going on in the example there.
- If you’re interested in peeking at metaprogramming, read through http://ruby-metaprogramming.rubylearning.com/. It’s not essential to building early Rails apps but you’ll definitely start running into it more in “the wild”.
- Glance through this Slideshare Presentation on SOLID principles.
Conclusion
In this lesson we covered some fairly random and intricate concepts but useful stuff to at least get familiar with, even if you’re not going to use it every day. Experience is the real key here — in the course of building awesome stuff you’ll run into the need for all of the things you just learned and it might just save you a lot of time and complexity in your code.
The more general principles like SOLID design and metaprogramming will be useful to you regardless of whether you stick with Ruby and Rails or move on to better and brighter things.
With all that completed, there’s not much else to go… it’s time to get started on your final project!
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
- A video from Yehuda Katz on Rails Security
- See the first solution to this SO question for a nice way to work with multiple layouts that use classes to trigger different CSS styling.
- Ruby Metaprogramming
- SO post on design patterns in Rails (2010)
Project:
Final Project
There’s a pretty popular social networking app you should build. They may have made a movie about it.
Project: Ruby on Rails Final Project!!!
Don’t forget to use Git to save your projects!
Project: Building Facebook
You’ve come a long way, congratulations! At this point, you should feel comfortable with building new Rails applications, modeling data, and working with forms. This project will require you to put all your newfound knowledge to the test. It should serve as a great portfolio piece for what you’re capable of. It’ll take some thought and time but it’s certainly within reach of your skills.
You’ll be building Facebook. As usual, any additional styling will be up to you but the really important stuff is to get the data and back end working properly. You’ll put together some of the core features of the platform — users, profiles, “friending”, posts, news feed, and “liking”. You’ll also implement sign-in with the real Facebook by using Omniauth and Devise.
Some features of Facebook we haven’t yet been exposed to — for instance chat, realtime updates of the newsfeed, and realtime notifications. You won’t be responsible for creating those unless you’d like to jump ahead and give it a shot.
Your Task
Build Facebook! You’ll build a large portion of the core Facebook user functionality in this project. We won’t be worrying about the Javascript-heavy front end stuff but you won’t need it to get a nice user experience.
You should write at least a basic set of integration tests which let you know if each page is loading properly and unit tests to make sure your associations have been properly set up (e.g. testing that User.first.posts
works properly). Run them continuously in the background with Guard (See the Ruby on Rails Tutorial Chapter 3.6.2).
This project will give you a chance to take a relatively high level set of requirements and turn it into a functioning website. You’ll need to read through the documentation on Github for some of the gems you’ll be using.
Keep the following requirements in mind. We’ll cover specific steps to get started below this list:
- Use Postgresql for your database from the beginning (not sqlite3), that way your deployment to Heroku will go much more smoothly. See the Heroku Docs for setup info.
- Users must sign in to see anything except the sign in page.
- User sign-in should use the Devise gem. Devise gives you all sorts of helpful methods so you no longer have to write your own user passwords, sessions, and
#current_user
methods. See the Railscast (which uses Rails 3) for a step-by-step introduction. The docs will be fully current. - Users can send Friend Requests to other Users
- A User must accept the Friend Request to become friends
- The Friend Request shows up in the notifications section of a User’s navbar.
- Users can create Posts (text only to start)
- Users can Like Posts
- Users can Comment on Posts
- Posts should always display with the post content, author, comments and likes.
- Treat the Posts Index page like the real Facebook’s “Timeline” feature — show all the recent posts from the current user and users she is friends with.
- Users can create a Profile with a Photo (just start by using the Gravatar image like you did in the Rails Tutorial)
- The User Show page contains their Profile information, photo, and Posts.
- The Users Index page lists all users and buttons for sending Friend Requests to those who are not already friends or who don’t already have a pending request.
- Sign in should use Omniauth to allow a user to sign in with their real Facebook account. See the RailsCast on FB authentication with Devise for a step-by-step look at how it works.
- Set up a mailer to send a welcome email when a new user signs up. Use the
letter_opener
gem (see docs here) to test it in development mode. - Deploy your App to Heroku.
- Set up the SendGrid add-on and start sending real emails. It’s free for low usage tiers.
Extra Credit:
- Make posts also allow images (either just via a URL or, more complicated, by uploading one).
- Use the Paperclip gem to allow users to upload a photo to their profile.
- Make your post able to be either a text OR a photo by using a polymorphic association (so users can still like or comment on it while being none-the-wiser).
- Style it up nicely! We’ll dive into HTML/CSS in the next course
Getting Started
- Think through the data architecture required to make this work. There are a lot of models and a lot of associations, so take the time to plan out your approach.
- Build the new postgresql rails app
$ rails new odin-facebook --database=postgresql
, initialize the Git repo, and update the README to link back to this page. - Work your way down the list above! Each step will involve a new challenge but you’ve got the tools.
- You can populate data like users and posts using the Faker gem, which is basically just a library of sample names and emails. It may just be easier, though, for you to write your own seeds in the
db/seeds.rb
file, which gets run if you type$ rake db:seed
.
Student Solutions
Send us your solution so we can show others! Submit a link to the Github repo with your files in it here using any of the methods listed on the contributing page. Please include your partner’s github handle somewhere in the description if they would like attribution.
- Adrian Badarau’s solution | View in browser
- Yuri Buerov’s solution
- David Janczyn’s solution | View in browser
- Aleksandar Rodić’s solution | View in browser
- Jason Matthews’ solution | View in browser
- Donald’s solution | View in browser
- Dominik Stodolny’s solution | View in browser
- AtActionPark’s solution | View in browser
- Alex’s Solution | View in browser
- Jeremy Mauzy’s Solution | View in browser
- dchen71’s Solution | View in browser
- James Kelsey’s Solution (No tests, Ajaxy) | View in browser
- Matias Pan’s solution (RSpec, Capybara, Ajax) | View in browser
- Add your solution above this line!
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
- For another take on this, here’s a gem-laden Facebook clone via Quora.
Step 5:
Conclusion
Holy cow, you’ve gotten to the end of the road! …Sort of.
Conclusion and Next Steps
You’ve reached the end of the scope of this course and should feel pretty good about your Rails skills. That doesn’t mean you should feel like you understand everything, but you should be able to build a Rails application with the kind of functionality which is actually useful in the real world. It probably won’t look too pretty, but that will come in the next few courses.
This isn’t the last course in the curriculum and you’ve got quite a way to go before hitting that “full stack” point, but it’s as far as we’ll get with Rails and it’s pretty darn far. Despite how far you’ve come, it’s up to you to keep building stuff, asking questions, and digging deeper into both Rails and best practices of software engineering in general.
At this point, you’ve got the Rails building blocks but the learning is never finished. Your first six months on the job as a Rails dev will involve learning at least as much information as you just did. The point of this course has been to get you to a place where you can start thinking about actually getting that first job.
Next Steps
This final lesson isn’t designed to explicitly teach new material, just point you in the right direction if you’d like to dig a bit deeper before moving on. Or maybe you’ll bookmark it and come back when you want to see where to head next in your Rails journey.
Rails is deep… there’s a lot going on behind the scenes and it will take a long time to actually understand how it all works and the best ways to use it. The best way to figure it out is to work for a company that uses it and get paid to learn. If that’s not an option, building your own stuff and reading on your own time can be a good substitute. There’s new information being created every day in blog posts, Stack Overflow posts, and podcasts.
A good first step is to reread the Rails Guides. There are some sections we skipped and some guides we never got to (especially in the “digging deeper” section). In particular, the following sections might be interesting:
Security
If you start working on more public-facing applications, security will become more important. Check out the Rails Guide on Security for more information.
Rake Tasks
Rake tasks are a special way of running scripts that can use your application. You’re already familiar with some like $ rake db:migrate
, but you can also create your own. This website uses a Rake task to populate the curriculum from its Github repo. Check out the Rails Guide on Command Line and Rake Tasks for more information.
Caching
Caching makes your application faster by reducing database calls. Check out the Rails Guide on Caching to learn more.
Books
Here are a few books that will take you a bit deeper as well:
- The Rails 4 Way by Obie Fernandez is a comprehensive guide to the framework.
- Agile Web Development with Rails 4 is sort of an in-depth guide combined with a tutorial that follows Agile practices along the way.
- Rails Antipatterns is a good best-practices guide.
Other Resources
- RailsCasts by Ryan Bates are incredibly valuable. Great ways to actually see the implementation of various gems or practices.
- GoRails alternative to RailsCasts.
- The RailsApps Project provides lots of great tutorials that walk you through building real-life scenarios like integrating Devise and CanCan with your app or building a payments backend.
- RubyFlow community blog will have some interesting stuff pop up from time to time.
Contributing
You know more than you think. Remember when we just said that you should keep building stuff? This website is completely open source and needs your help to improve. We have a dedicated group of current and former students who help add features and proofread the curriculum. The best part is that it’s completely public and free so you can watch or participate at whatever level you’re comfortable.
It’s a great way to start learning about agile development methodologies and to start doing meaningful development work in a friendly and supportive environment. So check out our Google Community and our Meetup Group to see what we’re up to. We’d love to have you get involved!
Conclusion
I want to emphasize again that the learning never really stops but also that you’ve come a long way. Stick around for the next few courses and you’ll take a good core and build some very interesting things. In the HTML/CSS course, you’ll learn to make your Rails applications look like actual websites instead of text dumps. In the Javascript course, you’ll learn how to take everyday web apps and make them much faster and more dynamic in the browser.
So there’s a lot left to go but it gets better and better. Stick with it!
Additional Resources
This section contains helpful links to other content. It isn’t required, so consider it supplemental for if you need to dive deeper into something
- How I Learned Ruby on Rails by Richardson Dackam
- A listing of Rails tutorials from Daniel Kehoe of RailsApps
- A list of some slightly longer Rails Tutorials by Jumpstart Lab
- The University of Texas Rails Course Online (incomplete/dated?)
- Free Online Webinars from buildingwebapps.com
- Rails Cheat Sheet by Tobias Pfeiffer
- Rails Best Practices list
- Building a Simple CMS in Sinatra Tutorial
- Why not to hardcode your application’s secret token in production
- How I Test by Ryan Bates
- Testing series on TDD and intermediate stuff
- Why use the
%Q
methods? - Ruby on Rails Tutor has free videos that highlight specific sections of Rails.