Terrible Blog

Because Terrible Labs loves you.

Previewing Emails With the Mail_view Gem

| Comments

Mailer specs are a great to verify that the emails sent from your Rails applications have the required data, links, and important content. But often a developer, or more likely the product owner, may want to see the emails to make sure they are properly formatted, read well, and are free of spelling errors.

Getting your application to send an email from a development or staging environment can be an onerous task depending on how much user workflow and data setup is required for a given email. This is where the mail_view gem can really help you out.

The mail_view gem lets us easily preview emails right from within your Rails application running in the development environment

Using mail_view in Rails 4.1+

Configuring mail_view

mail_view is built into Rails 4.1+, so there is no additional setup or configuration to start using it.

You can read more about support for mail_view in Rails 4.1 in the following links:

Setting up emails to preview

By default, Rails 4.1 expects the mail preview classes to be located in the test/mailers/previews directory. If you use the mail generator, a preview file will be created for you automatically. You create a class that inherits from ActionMailer::Preview for each email to be previewed.

1
2
3
4
5
6
class WelcomeMailerPreview < ActionMailer::Preview
  def welcome_investor
    user = User.last
    WelcomeMailer.welcome_investor(user)
  end
end

Previewing the emails

Browsing to http://localhost:3000/rails/mailers/welcome_mailer/welcome_investor will show you a preview of the email. But before you do that you will probably need to set up some data for the preview

Using mail_view in Rails prior to 4.1

Configuring mail_view

For Rails versions prior to 4.1, there is just a little work to do to get set up.

First you will need to add the gem to your Gemfile.

1
gem "mail_view", "~> 2.0.4"

Then you mount the mail_view engine into your application via the routes.rb file.

1
2
3
  if Rails.env.development?
    mount MailPreview => 'mail_view'
  end

I wanted to make the mail_view available on my staging server, so I used an environment variable to enable it.

1
2
3
  if Rails.env.development? || ENV["PREVIEW_EMAIL"] == "true"
    mount MailPreview => 'mail_view'
  end

With the engine mounted at mail_view, browsing to http://localhost:3000/mail_view will present us with a list of emails to preview. But before we do that, we need to set up the emails to preview.

Setting up emails to preview

You set up the emails to preview by creating a class that inherits from MailView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MailPreview < MailView

  def welcome
    user = User.last
    WelcomeMailer.welcome_investor(user)
  end

  def payment_confirmation
    payment = Payment.last
    PaymentConfirmationMailer.confirmation_email(payment)
  end

  def contact_us
    ContactMailer.contact_email("Joe Smith", "617-555-1212", "jsmith@example.com", "I have a question...")
  end

Listing the emails

Now that we have some emails to preview, we can browse to http://localhost:3000/mail_view will present us with a list of email preview links as defined in the MailPreview class. Mail Preview List

Providing data for the emails

Typically our emails are working with data from our database. The mail_view documentation describes some of the ways you can provide data to the mailer, using either actual data from the database, using a factory pattern, or providing a stub.

In the examples above, I am using data from the database. Each approach has its advantages and disadvantages, and it really depends on how you data is structured as to which approach you use. You can also mix and match the different approaches as you see fit.

Viewing an email

mail_view displays a preview of the email with the header information shown in the page header and the body in an iframe, as shown below. Mail Preview As HTML

If you have provided a text and html template for the email, a dropdown is displayed in the page header to allow you to preview the different formats. Here we are displaying the text version of the email Mail Preview As Text

Since the body of the email is displayed in an iframe, clicking on a link in the email will open the link inside the iframe. Mail Preview Open Link

Summary

The mail_view gem is a great tool to allow you to visually inspect the emails sent by your Rails application.

Motion-juxtapose: Now With Rails Support!

| Comments

Earlier this year, we released motion-juxtapose, a gem for using screenshots to test iOS apps built with RubyMotion. Today, we released version 0.2.0 with some bug fixes and support for Rails integration tests!

When running under Rails, the gem uses Capybara to capture its screenshots. Any Capybara driver that supports screenshot capture should work, though we’ve only tested this with Poltergeist so far.

In your spec_helper.rb, add:

1
2
3
require 'juxtapose/capybara'
# if you're using rspec, you can get the `look_like?` custom matcher with:
require 'juxtapose/rspec'

Now the Capybara page object will have a looks_like?(predicate) method that can call to make screenshot assertions:

1
2
3
4
5
6
feature "viewing locations", js: true do
  scenario "should only show books at first location" do
    visit location_path Location.find_by_name("Cambridge")
    expect(page).to look_like("books at Cambridge")
  end
end

Check out all the details over at the project’s Github page and let us know what you think.

Write Maintainable CSS

| Comments

Typical scenario #1: We’ve just spent several hours building an application feature. Now in the last part of the day we are tasked with styling the feature. We’re a little tired, it’s after lunch, and really nobody’s looking at the CSS anyway, so we can probably just do whatever is simplest to get the job done.

Typical scenario #2: We’ve just spent several hours modifying an application feature. Now in the last part of the day we are tasked with re-styling the feature. We’re a little tired, it’s after lunch, and we have little patience for mucking around in CSS. We open the stylesheets only to find that little attention was paid to the structure and organization of them. As a result we have to spend twice as long as we should combing through lines of CSS in order to figure out how our feature was styled in the first place. Our frustration with the current state of the CSS causes us to write even sloppier CSS to address today’s issue. We exacerbate the problem.

We write clean, maintainable application code. We do this because we know that the code will eventually need to change. Writing with change in mind informs our process. Yet with CSS we often let this discipline slip. We don’t spend the time to construct CSS the right way, choosing instead the path of least resistance. Perhaps because CSS is simpler than application code, we feel that it is below us and we can hustle through it without wasting too many brain cycles. Perhaps it’s just boring to write CSS and we want to get it out of the way. Whatever the excuse, it often leads to poorly-planned and un-maintainable styles. This leads to angst about writing CSS. Bad CSS taints our impression of all CSS. If we make a commitment to write more maintainable CSS, we will make our own lives significantly happier when we inevitably get back into those styles.

Here are some high-level concepts we should keep in mind to help write maintainable CSS. None of these are complicated, and may even seem common-sense. But are we always really following them? The broken window effect can quickly spiral out of control with CSS, so keeping the fundamentals in mind at all times will help keep us sharp.

How Global Is This Style?

This should be the first question we ask when styling any element. Instead of diving right into the CSS, we should take a few seconds to ask “does this element occur anywhere else?” 90% of the time the answer will be yes. At that point it’s up to us to determine if the style is better suited for a more global stylesheet, a mixin, or an extendable class. If it’s more efficient to create the style in one place first and only abstract it once it re-occurs, that’s fine. As long as we’ve made the decision to eventually globalize the style, we’re on the right path.

1
2
3
4
5
6
7
8
9
10
/* users.css_ */
#user-profile aside.menu {
  padding: 10px;
  border: 1px solid #ccc;
}

#user-profile aside.menu h4 {
  font-size: 12px;
  text-transform: uppercase;
}

This style looks fine initially. But before or after composing this CSS, we should take a quick look over the design to determine if any of these styles are more global. Let’s say we discover that there will be several side menus with the same border and padding styles. We can then make the aside style more global:

1
2
3
4
5
/* global.css */
aside.menu {
  padding: 10px;
  border: 1px solid #ccc;
}
1
2
3
4
5
/* users.css */
#user-profile aside.menu h4 {
  font-size: 12px;
  text-transform: uppercase;
}

DRY It Up

We don’t allow unnecessary duplicate methods to occur in our code; why then should we allow a set of CSS styles to occur more than once in our stylesheets? The most agonizing task when working in CSS is making adjustments to elements that are being styled from multiple places. Ideally we should only have to modify CSS in one place when making an update. Even if it feels like we’re writing a little more CSS initially in order to keep things dry, in most cases it’s way to go.

We don’t always know ahead of time where a duplication will occur; we may need to style a few elements and then factor out the common styles afterwards.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* Before */
input[type=text] {
  width: 150px;
  height: 30px;
  border: 1px solid #000;
  color: #ccc;
  font-size: 12px;
}

textarea {
  width: 150px;
  height: 150px;
  border: 1px solid #222;
  color: #ccc;
  font-size: 11px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* After */
input[type=text], textarea {
  width: 150px;
  border: 1px solid;
  color: #ccc;
}

input[type=text] {
  height: 30px;
  border-color: #000;
  font-size: 12px;
}

textarea {
  height: 150px;
  border-color: #222;
  font-size: 11px;
}

The refactor creates more CSS than the original, but is is more manageable. If we need to change the width, border, or color of these form elements, we now only need to change them in one place.

Break Up Global Styles

global.css can become quite a large file if left unmanaged. Oftentimes there are groups of global styles which can be split off into separate files. Form styles are a good example. Typically the majority of form element styles will be consistent across our app, and they usually require a significant amount of CSS. Moving these form styles out of our global stylesheet and into a global feature stylesheet helps keep our styles organized and our files as small as possible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Keep in global.css */
h1 {
  font-size: 24px;
}

aside.menu {
  padding: 10px;
  border: 1px solid #ccc;
}

/* Move from global.css to forms.css */
form input[type=text] {
  width: 150px;
  height: 30px;
  line-height: 30px;
}

form textarea {
  width: 150px;
  height: 150px;
}

Don’t Start With the Home Page

This sounds a bit dramatic, and it may not be possible given project and client needs. But the point it demonstrates should not be overlooked. If establishing global styles early is a priority (as it should be), beginning our CSS work on the home page can present a challenge. If there is one page in our app that contains unique design characteristics or diverges from the global styles, it’s the home page. A lot of effort is dedicated to styling the home page. If we start there, when we move on to an inner page we will find ourselves saying “this style is like the home page style but it differs a little.” In fact the opposite is typically true: the home page often differs from the global styles, with some similarities. Using the home page for establishing canonical styles can therefore confuse the process.

Ideally we should start our CSS work on an internal page full of global style elements. Conveniently, our app’s core functionality is usually contained in these inner pages, and that core functionality is typically the starting point for the development process. Though it may feel awkward - for our client as much as ourselves - to initially avoid the homepage, it can make for a more streamlined process in the long run.

Write With Refactoring In Mind

The most elegant solution is not always immediately obvious. As long as we keep our eyes open for a better solution, we will continue to keep our CSS robust and flexible. We should approach our CSS with the intent of refactoring it as soon as it is appropriate. We constantly refactor our application code, yet too often we leave crummy, outdated CSS to rot. Taking the time to refactor CSS makes our lives exponentially better when we inevitable dip back into the styles.

Stay Disciplined

As a whole we are too lenient with CSS. As we all know, many hours can be sunk into a style update due to poorly-maintained CSS. Part of the difficulty in keeping CSS up to a high standard is the lack of outside attention paid to it. In the application world our code is under much more scrutiny than is our CSS. The discipline to keep the ship righted must then be self-imposed. It is in our (and our clients’) best interest to keep a sharp eye on our styles. We should hold our CSS to as high a standard as we hold our code.

Setting Up a RubyMotion Project on Travis CI

| Comments

It’s pretty easy to set up Travis CI to run tests for RubyMotion projects, but there are few gotchas we encountered the first time we did it.

Here’s what the generic .travis.yml file we start out with looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# setting the language to objective-c tells Travis to use an OS X server
language: objective-c
install:
  # we use motion-config-vars (https://github.com/jamescallmebrent/motion-config-vars)
  # to manage our app's environment settings (API key, server addresses, etc) and it's a
  # good idea to have a bare bones copy of this for Travis, so you don't have any actual
  # sensitive keys in your git history
  - cp resources/app.travis.yml resources/app.yml
  - cd /usr/local
  # we wrote motion-juxtapose (https://github.com/terriblelabs/motion-juxtapose) for
  # screenshot-driven tests, but found that we needed a specific version of imagemagick
  # for it to work well on travis machines, so we'll use homebrew to install that version
  - git checkout 870d5e9 Library/Formula/imagemagick.rb
  - brew install imagemagick
  - cd -
  # RubyMotion is installed on Travis images, but the version is usally not the same as
  # what your app is doing. so, we'll update the RubyMotion install and need to ensure
  # the directories it's installing to are writeable by the travis user.
  - sudo chown -R travis ~/Library/RubyMotion
  - mkdir -p ~/Library/RubyMotion/build
  - sudo motion update --cache-version=2.30
  # install the app's dependencies
  - bundle install
  # if you're using cocoapods, we'll install them now. cocoapods generates *very* verbose
  # output, which can actually put your Travis build over the output limit and cause the
  # build to stop. we'll redirect standard out to a file to avoid that.
  - bundle exec rake pod:install > pod_log.txt
script:
  # finally, run our tests!
  - bundle exec rake spec

Testing a RubyMotion App With a Rails Backend

| Comments

Or, “those scars look really neat, where did you get them?”

Learning how to test RubyMotion apps can be daunting if you’re coming from a server-side programming background, especially one like Rails with a mature ecosystem of testing tools and community wisdom. Full-stack integration testing—firing up the entire system and putting it through through its paces as a user would—can be particularly challenging.

We recently wrapped up an engagement with one of our favorite clients, MeYouHealth, during which we needed to build a way to sanely test a RubyMotion app backed by a JSON-serving Rails backend. I’ll cover both the strategies we tried and discarded as well as our most successful approach.

Frank and Bacon

A brief RubyMotion testing aside: there are two libraries we use to write tests for our RubyMotion apps.

  • MacBacon is an rspec-esque library that ships with RubyMotion, which we use to write model and controller tests for individual components of the app.
  • Frank is a testing framework that fires up your entire app and walks through Cucumber-esque scenarios written in Gherkin, using Apple’s UIAutomation framework to drive the app from the outside. We use this to write black-box integration tests.

For both of these types of tests, we needed a way to mock out the JSON responses from our backend.

What Didn’t Work: Stubbing and VCR

Stubbing HTTP requests

Our first approach to making sure our tests didn’t depend on the backend was to simply stub out the HTTP responses in our Bacon specs using webstub. This worked, but it quickly became a pain to keep the stubbed responses in sync with the backend under active development. When they’d fall out of sync, debugging what was wrong in the tests wasn’t straightforward.

Worse, while technically possible to use webstub for Frank tests, to do so would have involved some signification contortions. Because Frank itself runs outside the app, the only way of stubbing is to add methods to the AppDelegate class and call them using Frank’s remote execution, doing so for each request we wanted to stub. Yikes.

VCR-esque HTTP Recording

The next tack we tried was recording responses from the server once and playing them back, inspired by VCR. VCR itself doesn’t work in RubyMotion (as with most regular Ruby gems), so we used a custom recording proxy server written in Go with a thin Ruby wrapper for driving cassette use inside tests. This would record HTTP interactions with a local test server once, then replay them each subsequent time.

This worked, and let us run our Frank specs without a live backend. However, it suffered from the same skew between backend development and recorded cassettes. Changing modeling on the backend necessitated either some tricky editing of the cassette files or setting up the scenario again and re-recording the whole scenario. Time-sensitive data became tricky as well, with the timestamps being fixed in the cassettes once recorded. Not great.

What Worked: Remote Fixture Loading

First, we stopped trying to emulate actual HTTP tests in our Bacon controller and model specs, instead favoring use of dependency injection to test components in isolation. Any testing of HTTP concerns was deferred to the integration tests.

Next, to get our Frank features in shape, we built out a system to let us talk to a local instance of the backend and selectively load small scenarios for each individual feature to run against.

We’ve put together a pair of example applications to showcase this approach, along with instructions on how to get up and running. Note that while our example iOS app is written in RubyMotion, since Frank works independently of the app, there’s no reason this can’t be adapted for Obj-C or Swift iOS apps.

How It Works

  • On the Rails side, we first run a script that starts Rails in test mode and then listens for commands on a named pipe.
  • We then run the Frank tests on the client side. Each Frank feature that has a tag of the form @api_fixture_NAME will push a command over the named pipe for the Rails instance to load and run a scenario file with the specified NAME.
  • The scenario files are just plain Ruby files where we create the ActiveRecord objects that feature requires.
  • After the scenario file is loaded, the feature runs normally, with the app talking over HTTP to the backend with no stubbing involved. Each feature is now running against a known set of data and working with the actual APIs that the server is exposing.
  • The test database is wiped at the start of each test, so as to provide a clean slate and prevent state bleeding from one feature to another.

Disadvantages

This isn’t all roses.

For one, it’s slow. This is a problem with any form of iOS testing, as the app needs to be compiled and launched in the simulator before the tests can run, and it’s exacerbated here by the time it takes for the server’s state to be set up and torn down in between features.

It also adds complexity to the testing process by requiring you to have the Rails environment up and running for the Frank tests run at all. This also means some extra work to set up on a CI environment like Travis.

So It’s The Worst Approach, Except For All The Rest

We’re overall pretty happy with this approach: it lets us do full-stack integration testing without tearing our hair out trying to manage a bunch of mocked state. It also does a great job of letting us know when the client’s expectations of the API have gotten out of sync with reality on the server side. Despite the downsides it’s still a huge win in our minds.

Objective-C Method Syntax Primer for the Short-attention Span Rubyist

| Comments

If you’re a Rails developer coming to RubyMotion with no Objective-C experience, you’ll still need to be able read enough Objective-C to follow examples from the community. Even with Swift on the horizon, the reams of Objective-C examples floating around the Internet and books aren’t going anywhere and can be valuable to understand.

This doesn’t aim to be a comprehensive guide to Objective-C, but rather to get you just enough information to visually parse example code.

Method signatures

A method signature with no arguments in Objective-C looks like:

1
- (BOOL)isViewLoaded

The - mark at the beginning indicates this is an instance method; class methods are indicated with a +. The (BOOL) is the type of the method’s value (here, a boolean).

Calling methods

In Objective-C, methods are called using infix notation. The Ruby

1
controller.isViewLoaded

is equivalent to

1
[controller isViewLoaded]

Methods with named arguments

Objective-C methods can have named arguments. This UITableViewDelegate methods:

1
2
3
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Become the following Ruby methods:

1
2
3
4
5
def tableView(tableView, heightForRowAtIndexPath: indexPath)
end

def tableView(tableView, didSelectRowAtIndexPath: indexPath)
end

Note that these named parameters are actually a part of the method’s name; that is, different named parameters constitute a different method. The method names have the parameters separated by colons, like: tableView:didSelectRowAtIndexPath and tableView:heightForRowAtIndexPath.

This looks a bit funny when translated into Ruby, as a first glance would seem to indicate you’ve defined the same method twice. These methods are called just like you’d call methods with named parameters (in Ruby 2.0 and up) or optional hash arguments. For example, a UIViewController implements:

1
- (void)setEditing:(BOOL)editing animated:(BOOL)animated

We’d call this method in Ruby by:

1
instance.setEditing(true, animated: false)

Go rake, young Rubyist!

From here, you can dig deeper into Objective-C with Apple’s language docs, but you should now know enough to grok most of the examples you’ll run across in the wild.

Driving New Product Development at an Established Company

| Comments

It’s clear that the only way for a company to survive over the long term is to successfully evolve the company’s product offering. Companies that have rested on their prized revenue streams found themselves on a slow death march to oblivion. As an example, take a look at former Boston area titans: Wang Computer, Digital Equipment Corporation, and Polaroid.

The current success stories, that everyone likes to talk about, are Google and Apple. Google has been successful in evolving their product offering by investing in opportunities that have been tangential to their main business of search. Apple revived itself by transforming their hardware and software into indispensable technology for the masses.

At Terrible Labs we’re constantly trying to evolve our own product offering by being current on new technologies and design practices that will better help our clients solve their business problems. One example of this has been our effort to bolster our mobile design and development service offerings. Since making that investment, we’ve seen our mobile business grow from nothing into nearly 50% of our revenue each year.

Introducing Motion-juxtapose

| Comments

We’re big on RubyMotion at Terrible Labs. Over the last year since we’ve adopted it, we’ve found it to be a fantastic way to write iOS apps in a language we love without compromising on a native experience. Along the way, we’ve developed some nifty tricks we’d like to share with the rest of the world.

Today, I want to introduce motion-juxtapose, a library for adding screenshot-driven assertions to your RubyMotion tests.

4 Ways We Invest in Our Team

| Comments

Building a sustainable business from scratch is tough. For those who have successfully built a business, maintaining and growing that business can prove to be even harder.

As a design and development shop, the lifeblood of our business is designing and building products for clients. If our business is going to grow, we need to add designers and developers to our team, and the only way to do that is to bring in more client work.

In order order for us to bring in more clients we need to make sure that our services offering appeals to our prospective clients. Because the technology landscape changes so rapidly, the only way for us to ensure we’re providing the best services is to invest in our team’s learning and growth.

I’ve previously written about our struggle to find the right balance between client work and investing in our team. As we continue to figure it out, here are some things we’re trying out to help our team learn.