Zero to (with analytics!) in 8 Hours

Reading Time: 6 minutes

I had a limiting belief that went something like this:

A multi-functional app takes days to build, if not weeks, months, or years.

For many multi-functional apps, this is true. That said, it’s always useful to challenge one’s limiting beliefs about their craft.  What better way to do that than to code a multi-functional app in 24 hours or less?

The app creates links businesses might use to analyze where clicks to their website come from: it has  visit tracking for each link, geographic tracking for each visit, and a graph how many visits are coming from each link.

And yes, it’s real: you can make an account and use it, if you want to :). Check it out on Heroku, or see the code on Github.

Pictures below, plus an hour-by-hour breakdown:

Hour 1: Building the Structure

I entered

“rails new url-mgmt-app –skip-test-unit –database=postgresql” into my terminal to make the new app.

Then came “rails g model Link target_url slug” to make the model for my main resource—the links—and “rake db:create” to make a database for them. The nouns after “Link” are the attributes—it’s just a shortcut for making a migration file and adding the attributes to a model.

I also made a model for each visit to the website: We’ll want to count and track these.

I used “rails g migration AdjustAttributesOfLink,” and the same for Visit, to build migration files and make sure all of the attributes were correct for my models. Sometimes I get excited and forget to specify the data type of my attributes in the terminal, so I have to make a migration file and tell my program that half of my attributes shouldn’t actually be stored as strings (the default).

Hour 2: Installing Devise

I used a gem called Devise to handle the User model, logins, user authentication, and encryption. There are advantages to hand-rolling this, but speed ain’t one of ’em. As long as I could live with the fact that I’d have to have a separate signup page, rather than putting signup fields right on the homepage for an unauthenticated user, devise would do me just fine.

Hour 3: Setting up Database Relationships and Starting the RESTful Actions

How do all the models relate to one another? Well, a user has many links, which they’ll keep track of on a homepage for themselves, and a link has many visitslater, we’ll be using visit.count for each link id to determine how many times each link has been hit. Inside the user model I added “has_many :links” and inside the Link model I added “has_many :visits.”

Thanks to Rails shortcuts—like the fact that “resources :links” in the routes file automatically creates all seven RESTful routes—setting up the routes was a breeze.

Hour 4: Setting up Controller Actions and Views

This hour turned out to be a bit harder. I’ve only implemented all seven RESTful actions for a resource a single-digit number of times in my life so far, so that still sometimes presents challenges. Each link, when visited, needed to redirect to the target_url, and the visits needed to be counted in order to do analytics later. The homepage needed to show a little tour plus a sign-up button if no one was logged in, and it needed to show the user’s dashboard if a user was logged in:

Screen Shot 2014-07-23 at 12.45.34 PM

This was probably the fullest hour.

Re: the sign-up page: this is a view provided by Devise, and it’s not very easily customized. My attempts to do so in this hour failed, for the most part. This was the fullest hour of changes, I think.

Hour 5: Styling

A little bootstrap here, a few custom CSS classes there, and presto! It doesn’t look like it was built in 1996 anymore. I got my background from Check it out.

Hours 6 and 7: Implementing Geocoder and the Google Maps API

I wanted the app to show each user the geographic locations from which people were clicking on their tracked links. To do this, I collected the IP address for each visit, then added the geocoder gem to the application and used it to convert that IP address into latitude and longitude coordinates.

I won’t lie: this took some tinkering. I needed to learn the syntax for using geocoder inside the application. That said, once that was done, the Google API made it laughably easy to show a map pinpointing the locations of the visits.

Screen Shot 2014-07-23 at 12.45.55 PM

Here I am visiting the site from 1871 in Chicago.

A note on this: to test this feature, I had to deploy to heroku. This is because, when I tested the app locally, it saw my IP address as—the home default—and couldn’t map it to a geographic location. One could test the conversion and mapping features by just entering a dummy IP address into the code, but a) that wouldn’t test whether the correct IP is being drawn, and b) it would be so easy to accidentally leave that in the code instead of replacing it with “request.remote_ip” upon deploying.

Hour 8: Adding some Analytics and Tying up Loose Ends

By issuing SQL queries to get the view counts of all of the links that led to the same URL, I was able to get a list of all the links for a target URL, and what percentage of tracked traffic came from each of them. Then I installed the chartkick gem, which gave me the option of entering my data and rendering a chart in Google Charts. The result:

Screen Shot 2014-07-23 at 12.46.12 PM

This final hour also comprised several little fixes: a uniqueness validation for each shortlink, for example, so someone doesn’t make the same link as someone else and then receive no clicks as their link redirects to someone else’s page. I wonder whether a functional app built and deployed in this amount of time will turn out to be missing crucial details that just get overlooked when one is moving at speed. I suppose I’ll find out, won’t I?

That said, I did a good deal of manual testing on this thing (as much as one person can do, mind you), and it seems to me to handle all the sad paths and edge cases correctly.

So that’s where you come in, rest of the internet. Feel free to use the tool, and if you discover a problem with it, let me know!


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.