Google Analytics provides solid, aggregate statistics for your Rails app. It answers questions like, “How many visitors do I receive a day?” and “Which parts of my app are most popular?”
It cannot track individual users over time, however. Questions like, “How long does the average user remain active over time?” or “How long does it take the average user to go from a free to a paid account” require user analytics.
Services like Mixpanel and KISSMetrics specialize in user analytics, offering robust tracking and reporting for a fee.
There is another option, a free, open-source Ruby gem (technically, a Rails engine) called Ahoy. In just a few minutes, you can have robust user analytics for your Rails app.
Let’s walk through an example; say that on our site we want to track visits and actions for each user.
First, install Ahoy and perform the post-installation steps. This takes only a few minutes.
Visit tracking starts immediately after you install Ahoy. You can customize the length of each visit (i.e. after how long does one visit turn into two); it defaults to 4 hours.
Ahoy automatically ties each visit to a user. You not only know how many visits you receive each day, but which users visit the most. Already, we have user analytics.
ahoy.track("Added todo item");
If the user takes an action handled by your Rails code, log it with Ruby:
Mixpanel and KISSMetrics offer advanced reporting out of the box, but have a cost and require you to send your user data to a third party. If you choose to leave either service, extracting your data in a useful way is difficult.
Ahoy is free and your data stays local, but you’ll spend time creating a stats dashboard and reports.
There is no right answer, but while evaluating user analytics tools, be sure to consider Ahoy alongside the paid options.
Here are some hard lessons I’ve learned maintaining a Rails app on EngineYard. It’s an extremely reliable product with great support, but there are a few nuances. I’d love to save you time by telling you these up-front. I’ll update this over time.
First of all –
Do you host your app on GitHub? If so, link your GitHub account to EngineYard for breezy deploys. When we want to deploy, we click Deploy right from the EngineYard dashboard and it pulls our latest master from GitHub.
Hop onto your repositories by SSH on your computer, just to get that initial configuration out of the way. Use the “automated SSH link” discussed in the link.
Install the Engine Yard CLI. You’ll need it to deal with some failed deploys.
Type gem install engineyard into the terminal if you’re on a Mac
Dealing with a failed deploy
Look at the log file. If you’re lucky, you’ll see a message containing the word “relax.” This means that the deploy failed early enough to not affect your application. Find the issue in the log and solve it.
Type ey web enable into the terminal if you’re on a Mac
Learn how to clone your environment
We’re going to set up a staging server for Cook Smarts, and I’ll post about that. In the mean time, read over the cloning guide. A couple of gotchas:
You may need to request an additional IP address if you don’t have any available, which you can do by clicking the + button near a region on this page
Remember to snapshot your environment right before you clone it. The clone takes your app and data from the latest snapshot.
Reasons to clone: you need a staging environment, or you need to test something quickly before you put it online.
Consider a staging environment, maybe
Do you need a separate staging server? Decide whether you want to keep it running all the time or just when you need to test new functionality. Choose a cheaper configuration for your staging server, particularly if you keep it running.
At Cook Smarts, we keep a separate staging environment but only have it on when we need it. This saves a significant amount of money.
Know what to do if you get this scary e-mail
We have received the following notification from Amazon that one or more of your Engine Yard Cloud instances may be affected by a maintenance period
At Cook Smarts we rely on external services for payments, image processing, and more. Sometimes, the app will fail to reach a service. Perhaps the service is down or there’s a network error somewhere along the line.
How can we tolerate such errors with a minimum impact to the user?
Here’s an example of how we addressed a recurring error with an external service:
A user can export a recipe as a PDF, including an image of the meal.* We retrieve the appropriately-sized image form reSRC, our external image processor.
Occasionally, the connection to retrieve the image times out, preventing the image from importing into the PDF. Before, this caused an exception, preventing the user from exporting the recipe at all.
For a better user experience, we now show a friendly error message in place of the image.
To show the friendly error instead of a fatal exception, we use ‘begin’ and ‘rescue’ in Ruby, in the midst of our Prawn PDF code.
Ah, the humble nutrition label. Since it was introduced in the 1990’s (in the U.S., anyway), it’s been pretty much ubiquitous. We see them everywhere, whether we understand them or not.
They’re particularly puzzling on foods with multiple ingredients. Looking at a nutrition label and an ingredients list side-by-side, you might guess which ingredients contribute the most to each nutrient, but you may be wrong.
Why am I talking about nutrition on a web development blog?
We implemented nutrition labels for Cook Smarts meal planning app, and put a twist on the classic. In addition to showing a nutrition label for every recipe, we show which ingredients contribute the most to each nutrient.
For instance, below are the nutrition facts for Orange-Sesame Beef Stirfry. By expanding the total fat, I can see that the #1 and #2 contributors are the flank steak and the cooking oil.
If I were counting carbs, I could expand total carbs and perhaps cut back on the rice.
Since we integrated the USDA’s robust nutrition database into Cook Smarts’ recipe editor on the back-end, we had this per-ingredient data. Instead of just exposing the recipe’s total nutrition facts, we tried to think of ways to go a little deeper. This is our first attempt at doing so!
The USDA database is huge, so we brought it onto a separate server that we interface with using our own API. It’s working well, and keeping the extra load off of Cook Smarts’ primary app server. More on our first attempt at service-oriented architecture soon!
In the reSRC image URL, we set the image’s width to 400px, and took a 133px slice through the middle of it.
Surely, we could also have done this with a tool on our server like ImageMagick, but using reSRC was faster than rolling our own thumbnails.
Showing different images on desktop and mobile
We had to find a way to load different images on desktop and mobile, in order to achieve the crop described above.
Images won’t load right away, particularly on a phone.
Unless you specify the width and height of an image in advance, the page will jerk around as each image loads.
We don’t not know the width and height of the image in advance since the site is responsive, but we still wanted to avoid page jerk.
We do know the proportion of the photos (the relationship between width and height), so we used the padding-bottom technique from Smashing Magazine. With this technique, knowing the proportion has the same effect as knowing the exact width and height, leaving the proper amount of room for the images before they load and eliminating page jerk.
… and on mobile, which is a bit different since we’re only taking a center crop:
To get the proportion (the % above), we divided the height by the width and multiplied by 100. The proportion is always the same no matter the image’s width.
In closing, content is paramount
Web projects are much more achievable when the content is great. In this case, I was lucky to have beautiful pictures of food. Had Jess not taken pictures of every Cook Smarts meal from the beginning, the visual archives would not have launched as quickly.
Want a screencast about the techniques above? Please leave a comment and let me know, or tweet me @coreyITguy.
To see the archives in their glory, sign up for a test drive account on Cook Smarts.
When redesigning the Cook Smarts meal planning app, we knew we had to handle images in a smarter way. Pictures of food are very important to the site. They make it easier for people to navigate to familiar dishes, and give an idea of what to expect when cooking them.
We have hundreds of high-res images stored on Amazon S3. We were missing two things: thumbnail-sized images, and a way to determine which size image to serve based upon the user’s screen size.
I’ve prepared a screencast to show you how easy it is to implement reSRC.
Plug-and-play solutions like this make it easy for any web site to use responsive images, without coding. We may eventually generate our own thumbnails and serve the proper sized images through media queries, but reSRC allowed us to go responsive with our images in less than an hour, for about $30/month. That is pretty remarkable.
The recipes on Cook Smarts include videos that explain techniques such as seasoning and tenderizing chicken, quick-cooking potatoes, and chopping eggplants.
Prior to the redesign, the videos were linked within the text of the recipe, bringing the user to the Vimeo page in a separate tab. On a phone, looking at a very quickly was a bit difficult, requiring switching back and forth between tabs.
We looked for a smoother way for people to enjoy videos, and found a few techniques that helped.
Label video links
We added a video icon after each video link, using a bit of CSS and FontAwesome.
This bit of code looks for a link to a YouTube or Vimeo video, and adds a video camera icon next to it. Show the video immediately, without leaving the page
Opening the YouTube or Vimeo page in a separate tab was a waste of the user’s time. Instead, we used FancyBox 2’s media helper to open the videos in a modal popup.
When the user clicks a video link, the video pops up in the same page and immediately starts playing.
First, we add a class called fancybox-media to all video links. In the future, we may do this in the back-end rather than on the client, but this was much faster and takes care of past, current, and future recipes.
The goal of this was to make video more seamless for the user. It works on desktop and mobile, thanks to FancyBox’s awesomeness and Vimeo’s and YouTube’s mobile support.
Embedding the videos on the page itself was of course another option, and we may still do that. But clearly-marked video links in the recipe, which do not require the user to leave the page, seemed to be a clear next step.