Skip to content
Jesse Farmer edited this page Jul 31, 2014 · 7 revisions

URL Shortener

Getting Started

The README.md file contains instructions on how to create your own copy of this project.

Useful Commands

  1. rake -T

    Print out all available rake tasks w/ a small description of each.

  2. rake routes

    Print out Rails' current "routing table" as defined by routes.rb

  3. rake spec

    Run all the automated RSpec tests for this project (aka "the test suite").

  4. rake db:setup

    Run this on a fresh Rails application to set up the databases. Note: database.yml must be configured correctly.

  5. rake db:migrate

    Run all outstanding database migrations, ensuring your database schema is up to date. You'll need to run this every time you create a new migration or pull down code that includes a new migration.

Iterations

This project is structured as a sequence of iterations, each of which builds on previous iterations. We do not expect students to complete each and every iteration. Rather, they serve three important roles:

  1. Models for good engineering and product management, i.e., what do we build, in what order, and why?
  2. Natural checkpoints to ask for a code review or other feedback
  3. The ability to accommodate students with different interests, skill levels, and time constraints.

[v0.1] The Current Version

Note: This version is already built. It's what you'll get when you clone the repository! v0.2 is the first version for you to build.

In this version

  • A user may create a Link by submitting a destination URL to the site
  • A user may see a list of all Links submitted to the site
  • Every Link has an auto-generated short URL, which a user may visit to be redirected to the original destination URL.

In short, it's like the bare minimum functionality of bit.ly.

[v0.2] Basic Click Tracking

In this version, we'll add basic click tracking so that we know how many people have clicked on each of our links. To do this:

  1. Add a new integer field to the links table called clicks_count with a default value of 0 and ensure it can't have a NULL value. Do this by running

    $ rails generate migration AddClickCountToLinks clicks_count:integer
    

    Edit the migration file to set the default to 0 and disallow NULL values.

    See the ActiveRecord Migrations documentation for information on how to do add a new field to an existing database table. You'll want to use rails generate migration to create the appropriate migration, which itself should contain a call to add_column. Hint: Search for these keywords in the documentation.

    Remember, run

    $ bundle exec rake db:migrate
    

    to run a migration after you've created it.

  2. Add the appropriate validations to the Link model.

  3. Create a new instance method called Link#clicked! on the Link model which increments the value of clicks_count.

  4. Call Link#clicked! in the LinksController#show action.

  5. Show the clicks_count for each link on the homepage.

  6. Add appropriate model tests to spec/models/link.rb so that we know Link#clicked! is doing what we expect.

  7. Add appropriate controller tests to spec/controllers/links_controller_spec.rb so that we know the controller is incrementing the click count.

[v0.3] User Authentication

Add support for user authentication and user accounts using ActiveRecord's has_secure_password feature. Please don't use something "off the shelf" like devise. Right now, it's important we get a clear picture of all the major moving parts involved in "user authentication."

Note: Please read the has_secure_password documentation carefully. It describes what fields you need to add to your users table. It also contains a sample of very helpful code snippets around user authentication.

This feature requires that...

  • A User can register for the site using their email and password
  • A User can log in to the site using their email and password
  • A User can see the list of Links they submitted while logged in.

People should still be able to submit links without an account, though.

To create the User model, run

$ rails generate model User email:string:uniq password_digest:string

To add the user_id field on the links table, run

$ rails generate migration AddUserToLinks user:references

Again, remember to run bundle exec rake db:migrate to actually apply these migrations.

Do your best to create tests for the User model and any controllers you create. You'll likely be creating two controllers for this iteration: UsersController for creating new user-related actions and SessionsController for logging in and logging out.

Don't worry if you struggle to write tests around user authentication. Do your best and ask for feedback.

[v0.4] CRUD Operations

Now that we have support for user authentication, it makes sense to allow links to be updated or deleted.

  • As a User, I want to be able to edit the Links I submit.
  • As a User, I want to be able to delete the Links I submit.

Make sure a User can only delete or edit links they've submitted and not anyone else's. Do your best to write tests for these situations.

Note: You'll need to add new methods to the LinksController and add lines to routes.rb to tell Rails how to map URLs to those new methods.

Tip: At this point, you may or may not know what Rails expects. The easiest way to find out? Create a dummy project elsewhere containing a scaffolded-out Link model. You'll be able to look around this dummy project and see how Rails likes to organize things by default.

To create the dummy project, go to a new directory (outside your url-shortener project directory) and run

$ rails new dummy-project

Inside that the dummy project's root directory, run

$ rails generate scaffold Link short_name:string url:string

This will create a "fresh" Rails application with a fully-scaffolded Link model, controller, and views. You should use this as a reference for what the Rails conventions are.

[v0.5] Private Links

Sometimes, we won't want the world to know we love sharing links to cute animals. Let's enable some privacy. As a User, I want the option of marking the Links I submit as "private", so that they aren't listed on the homepage.

Here's the migration command:

$ rails generate migration AddPrivateToLinks private:boolean

Make sure you go into the newly-created migration file to set a default value for the field and disallow NULL values. Again, remember to run

$ bundle exec rake db:migrate

to actually apply the migration.

[v0.6] Advanced Click Tracking

Right now, we're only counting the raw number of clicks on each link. If you've ever used bit.ly, though, you know it tracks much more: referrer information, geographical information, when the clicks occurred, and so on. Let's add support for this while maintaining backwards compatibility with our pre-existing click_count interface.

On the database and model side, you'll need to do two things:

  1. Remove the clicks_counts column from the links table.
  2. Add a new table called link_clicks which will have one row per click containing whatever information we want to record.

Remove the clicks_counts column from the links table by creating a new migration as follows:

$ rails generate migration RemoveClickCountFromLinks clicks_count:integer

Create the LinkClick model and migration by running

$ rails generate model LinkClick link:reference referrer:string

Change the Link model as follows

class Link < ActiveRecord::Base
  # We want to write link.clicks and not link.link_clicks
  has_many :clicks, class_name: 'LinkClick'
  # ... code ...

  # e.g., link.clicked!(:referrer => request.referrer)
  def clicked!(click_attributes = {})
    self.clicks.create(click_attributes)
  end

  # Determine number of clicks by size of clicks association
  # vs. field directly in links table
  def clicks_count
    self.clicks.count
  end
end

[v1.0] You decide!

We have a pretty sweet URL shortener at this point. You decide what you want to do to take it over the finish line. Here are some ideas:

  1. Improve the user interface. We highly recommend Shay Howe's Learn to Code HTML & CSS.

  2. Add cross-Link tracking. Two users can add the same URL, but they're tracked separately. Modify the application so that if multiple users enter the same URL they all get distinct short URLs, but the application can answer questions like "How many redirects have we done to a specific URL?" and "How many times has a specific URL been shortened?"

    This will require a new table because a "long URL" and "short URL" are now in a 1-to-many relationship instead of a 1-to-1 relationship. That is, a "long URL" can have many "short URLs".

  3. Now that we have better tracking, add better reporting. Find a way to graph clicks over the last day, week, and month. What domains are the most common sources of traffic for a given link? Note: To make interesting graphs, you might want to insert lots of fake data into your database. The faker gem makes this very easy and it's already included in the Gemfile.