Learn Ruby on Rails as You Modify a Craigslist Clone

Gain a solid understanding of core Ruby on Rails concepts

In this interactive tutorial you're going to learn Ruby and Ruby on Rails fundamentals by modifying a Craigslist clone. You can view the source code on GitHub where you'll find a sample app to follow along.

This guide was written by Aidan Feldman. If you're interested in learning Ruby on Rails, you should take a look at our mentor-led course.

Get Started
Ruby on Rails Tutorial

Modify a Craigslist Clone

What to expect in this guide

People start learning Rails for all sorts of reasons. Whether you have been programming for years and want to give web development in Ruby a try, or you are a complete coding newbie wanting to see if programming is for you, Rails is a great tool to learn. Most of the resources in this guide assume no programming knowledge — more advanced readers may choose to skim the introductory sections of each to learn the particulars of Ruby and Rails.

In this guide, we are going to cover:

  1. The Rails landscape

  2. Installation of the necessary tools

  3. What is Ruby

  4. What is Rails

  5. Changing the structure of your database

  6. Models

  7. Interacting with your application from the command line

  8. Making souped-up HTML

  9. Adding URLs

  10. Handling requests

  11. Making reusable chunks of display code

  12. Building forms

  13. Where to go next

Before getting started, you should pick a goal. This tutorial will walk you though modifying a sample application, but the real test is when you apply these concepts to something unique. This could be a personal blog, or a site for your dog walking business... whatever! "Building a better Facebook" is probably a bit ambitious for a first project – keep it simple. Having a real problem to solve in the back of your mind will help keep you motivated, and allow you to ask yourself "how would this apply to my project?" as you cover each concept.

For beginners

It's been said that it takes 10,000 hours of practice to master a skill, and programming is a particularly difficult one – if it were easy, there would be a lot more programmers in the world. There's a quote:

Give someone a program, you frustrate them for a day; teach them how to program, you frustrate them for a lifetime.

Don't be discouraged if it isn't making sense. There are tons of resources, online and in-person, that can help you get unstuck.

What is Ruby on Rails?

Rails is a framework written in Ruby that helps you build web applications. There are a lot of concepts packed into that one sentence that may be new to you, but don't worry, we'll get you feeling cozy.

Ruby is a programming language. While there are many others (e.g. Python and Java) and they can mostly accomplish the same tasks, Ruby is a particularly readable and fun one, so you've made a good choice. If we were building a house, Ruby would be the raw materials: plywood, nails, etc. Rails is a framework written in (and for) Ruby – think of this as the frame for the house. It gives you certain parameters to work within, but you have a lot of flexibility about how the final product turns out. Just like the frame is built from the same raw materials that will be used to fill in the details of the house, Rails is written in Ruby, and you will add all of your application-specific features using Ruby (and HTML, and CSS, etc.).

Through your instructions in Ruby, Rails will take information stored in a database and send HTML to be displayed to the user in a browser. Let's get going!

The first rite of passage of programming is getting the necessary tools installed. Thankfully, there is a handy guide that describes how to do just that.

Install Rails

IRB, Scripts, and the Ruby Language

It's really tough to have a conversation if you don't speak the language, so Ruby is the next step on the way to building your first app. Like most programming languages, Ruby is written in source code files as text, which is then run one of two ways:

  • Interactively through the REPL (Read-Evaluate-Print Loop), which in Ruby is called IRB, i.e.

  • $ irb
    > Ruby.goes.here
  • Run as scripts, i.e.

  • $ ruby file.rb

One convention to note: lines that start with a $ (like above) means they are commands, intended to be run at the command line. Lines that start with # or are surrounded by <!-- ... --> are comments, just there as helpful info.

Give these resources a try to learn the basics of programming in Ruby:

  1. Try Ruby

  2. Ruby Bits

If you run into problems where you're not sure the state that your program is in, just remember: puts is your friend. If you aren't sure what the value of a variable is at a certain line, just print it out to your console.

Additional resources

A Framework for Ruby

Now that you have the basics down, you are ready for the main course: Rails! Gems are reusable plugins that are published by the community, the most popular of which is Rails. Rails itself is made up of many smaller gems.

Sample Application

Let's start with a super simple classifieds site called Thinklist (a Craigslist clone), where we can create and view individual listings. To get it set up, do the following:

  1. Download and unzip the starter application code

  2. Open up your terminal

  3. Navigate to the Thinklist directory (a.k.a folder) using the cd command (a.k.a. "change directory"), followed by the path (actual location may vary):

  4. $ cd ~/Downloads/thinklist-start
  5. Install the app's gem dependencies – which are listed in the Gemfile – using Bundler:

  6. $ bundle
  7. Set up the database:

  8. $ rake db:setup
  9. Start the server:

  10. $ bin/rails server
  11. Open the application in your browser: http://localhost:3000

You should now see something that looks like this:

Adding On

The application is fairly simple, but play around with it a bit to get a feel for it. We are going to use this application as a starting place, and learn some Rails by adding support for categories. Don't worry if you get lost – after each step, we will include:

  • A link to the code as it should appear

  • A link to the "diff" showing what changed

Open up the folder in your Sublime Text (or other code editor of choice) by dragging the folder onto the editor application icon. You will now see a bunch of folders and files – these are the guts of your Rails app. Let's get started!

Changing the structure of your database

In web applications, information is stored in a database. Think of a database as a bunch of interconnected spreadsheets, called tables. Take a look at the existing structure in db/schema.rb.

In an application using a SQL database (like Thinklist), each type of thing (users, products, etc.) will generally have it's own table. Let's get the category structure in place.


Use the Rails generate command to set up the migration, which contains instructions for changes to the structure of the database. This could include modifying an existing table (e.g. adding a column), or in this case, creating a new one. Run:

$ bin/rails generate migration CreateCategories


Open the newly created migration file, db/migrate/XXXXX_create_categories.rb. Here, we will need to specify exactly what we want changed, which in this case will be adding a categories table, as well as a reference (a.k.a. foreign key) from the listings so they can each be assigned a category. Add this to the file:

# modify db/migrate/XXXXX_create_categories.rb
class CreateCategories < ActiveRecord::Migration
  def change
    create_table :categories do |t|
      t.string :name

    add_reference :listings, :category

Confused about where to add your code? The first commented line in each code block indicates which file you should be working in, which might not exist yet. If you're still confused about where you should be adding code within the file, check out the "diff" link included below each block. Remember - the "code" link will show you the code as it should appear at that point, and the "diff" shows what was changed from the previous step.


Though the migration file has been generated, we now need to apply the change. Rake is another gem that lots of Rails-related commands are run through.

$ bin/rake db:migrate

Assuming the migration was successful, you will see the changes reflected in db/schema.rb.

Models are what deal with data in your application – they handle passing information to and from the database. You can see our (currently very simple) model definition for Listings in app/models/listing.rb.

Now that we have the database structure in place for categories, we need to create a corresponding model. The file and class name are the singular form of the table name (categories), and are case-sensitive.

# create app/models/category.rb
class Category < ActiveRecord::Base
  has_many :listings, dependent: :nullify

Models in Rails are built on top of a gem called ActiveRecord, so you will notice that your Category model inherits (the < part) from ActiveRecord::Base. The has_many line tells Rails that there is a relationship (a.k.a. association) between the listings and the categories. Don't worry about dependent: :nullify for now; it just tells your app how to deal with a record when its owner is deleted (in this case, the Category).

Now let's set up the other half of the relation:

# modify app/models/listing.rb
class Listing < ActiveRecord::Base
  belongs_to :category

  # ...

This tells Rails that Listing's can be assigned a category. has_many with a belongs_to is called a one-to-many relationship, because one Category can have many Listings, but a Listing can have at most one Category.

Interacting with your application from the command line

The easiest way to understand how models work are to interact with them in the Rails console. The console is IRB (which we've already seen), but you are able to make calls to your Rails application code. To open it, run:

$ bin/rails console

At this new prompt, type the following, then press ENTER to execute the line:


As expected, none exist yet. Let's create one:

Category.create(name: "Antiques")

Both #count and #create are class methods provided by ActiveRecord, but we can interact with individual instances/categories as well:

category = Category.last

Go ahead and create a few more categories. When done, type exit and press ENTER to quit the Rails console.

Making souped-up HTML

Views are the part of Rails that generate HTML to be sent back to the browser... in other words, what the user will actually see. In Rails, ERB templates are used to insert Ruby code into HTML files, so that you can generate pages depending on what record the user is viewing, whether they're logged in or not, etc. Helpers are methods that can be used within your views, whether provided by Rails or written by you.

We will want a way to see all of the categories, so let's add a dropdown to the navigation bar:

Replace the existing "Listings" link with:

<!-- modify app/views/layouts/application.html.erb -->
<li class="dropdown">
  <a href="#" class="dropdown-toggle" data-toggle="dropdown">Categories <span class="caret"></span></a>
  <ul class="dropdown-menu" role="menu">
      <%= link_to 'All', root_path %>
    <% Category.order('name ASC').each do |category| %>
        <%= link_to category.name, '#' %>
    <% end %>

There are a bunch of things to point out here. Besides the normal HTML, <% ... %> tags execute Ruby, and <%= ... %> tags output the result of the expression. link_to is a built-in helper that takes the text to display and the model to create an anchor tag to. The various attributes (class, role, etc.) on the HTML tags are there to apply styling from Bootstrap.

Bootstrap is a framework that can be used with any site to make styling pages easier – basically to give minimal, good-looking defaults for buttons, navigation, that work well on a range of browsers and screen sizes. For new projects, you can learn how to set it up here.

You'll notice, however, after refreshing the page, all of the category links go to #... a.k.a. nowhere. Modify them to link to the category page:

<!-- modify app/views/layouts/application.html.erb -->

<!-- before -->
<%= link_to category.name, '#' %>

<!-- after -->
<%= link_to category.name, category %>

We now get an error, "undefined method category_path". That page doesn't exist yet!

Adding URLs

When you visit a Rails website, the request comes in through the router, which determines the URL structure of your application. Let's add a URL to view all listings in a particular category.

# add to middle of config/routes.rb
resources :categories, only: [:show]

When the page is refreshed, you will no longer get an error, because we've now told Rails the URL structure for viewing a particular category. To see all URLs that your application supports, use this command:

$ bin/rake routes
      Prefix Verb   URI Pattern                  Controller#Action
    category GET    /categories/:id(.:format)    categories#show

When you click on an individual category, however, you will get an "uninitialized constant CategoriesController" error, because we haven't set up a controller to handle the request yet.

Handling requests

The router determines which controller action to send the requests to. After the controller receives the request, it then gathers up the models it needs, and renders the appropriate view. Create a controller for categories:

# create app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
  def show
    @category = Category.find(params[:id])

Similar to the Category model with ActiveRecord::Base, controllers in our app inherit from our ApplicationController, which in turn inherits from ActionController::Base. Instance variables (the ones that start with @) are used to pass data from the controller to the view.

Refresh the category page, and you should see a new error: "Missing template categories/show". /categories/ID is hitting the show action/method, which implicitly tries to render the corresponding view (notice that when we ran bin/rake routes previously, /categories/:id(.:format) corresponded to categories#show - that's the template it's looking for!). That doesn't exist yet, so let's put in that last piece.

Making reusable chunks of display code

Rails templates are organized by folders corresponding to the controller, and the filename corresponding to the action. The view for categories#show, for example, will live in app/views/categories/show.html.erb.

Let's say we want to make our list of listings display the same on the homepage, as well as on the individual category pages. We could copy-and-paste the code from the listings index page, but within an application, copy_and_paste == 'baaaaddd'. Instead, let's extract the code that handles rendering that part of the page, so it can be used in both places.

Take everything from app/views/listings/index.html.erb except the &lr;h1>...&lr;/h1> and move it into a new file called app/views/listings/_list.html.erb. Template filenames that start with an underscore are known as partials, which are intended to be used from within other views. Once the code is in there, change all of the occurrences of @listings to use a local variable (listings) instead (i.e. remove the @s). This will allow that code to be more portable.

Where the list code was within our existing template, have it render the new partial instead:

<!-- modify app/views/listings/index.html.erb -->
<%= render partial: 'list', locals: { listings: @listings } %>

After verifying that the homepage still renders correctly, go ahead and add the page to view a category, which will look a lot like the listings/index.html.erb template above, but using the category name as the heading instead.

<!-- create app/views/categories/show.html.erb -->
<h1><%= @category.name %></h1>
<%= render partial: 'listings/list', locals: {
    listings: @category.listings } %>

We want the ability to assign a category to a listing. Visit the form for creating new listings. Let's use the Rails form helpers to add a dropdown/<select> box to the form next to the other fields for the user to choose the category:

<!-- modify app/views/listings/_form.html.erb -->

<div class="form-group">
  <%= f.label :category %>
  <%= f.collection_select :category_id, Category.all, :id, :name, {
      include_blank: "Please select..." }, { class: 'form-control' } %>

Refresh the page, and you should see the new field present

Select a category and create a new listing. Did you get an "unpermitted parameters" error? This is because, for security reasons, Rails requires us to explicitly tell it what fields should be coming in from the form. Let's add :category_id to the list of accepted parameters:

# modify at bottom of app/controllers/listings_controller.rb
def listing_params
  params.require(:listing).permit(:title, :description, :price, :category_id)

This technique (and gem that handles it) is called strong parameters. params are the full list of values that the form has sent, and the require() and permit() filter that list to only the ones that should be allowed through to the controller's create action. Try creating another listing with a category, and it should save successfully.

To more easily see that the category was successfully assigned, let's display it on the listing page:

<!-- add to app/views/listings/show.html.erb -->

  <% if @listing.category %>
    <%= link_to @listing.category.name, @listing.category %>
  <% else %>
  <% end %>

More Rails

Feel like you're ready to strike out on your own? We didn't think so. There are a lot of pieces to understand when building web applications, and chances are it was a bit of a blur the first time the concepts were introduced. One piece of advice (c/o Mattan Griffel): as soon as you get through one introduction to Rails, do another one. The Rails Tutorial will focus on some additional topics, but even where they overlap, hearing the same thing explained two different ways will make it clearer. Also, you will feel super awesome for already knowing a lot of it. So, go ahead, and we'll see you back here soon.

The Rails Tutorial

Congratulations! You now understand all the fundamentals of building a web application in Rails. There are many many options of what to learn next, and it's turtles all the way down. Options include: