Sonar is a blog about marketing, code and coffee from Submarine.

UX advice for your Rails app

While building Submarine, a huge focus for me has been on creating a user experience that's simple and frictionless, and I wanted to share some of the things that I've learnt.

Undo options instead of dialog boxes

Rails makes it easy to pop a dialog box before a destructive action - so if a user clicks "delete", you can show a confirmation box in their browser, like this.

Dialog box

But those dialog boxes can be annoying, especially if you see them a lot. It's especially irritating for people who have lots of things to delete, and it slows down how quickly they can work. In short - it adds friction.

Instead, with Submarine, I'm making use of an undo option instead of a dialog box for elements that are commonly deleted, like notes and tasks. Here's what it looks like:

Undo option

How to do it

Coding this from scratch is doable - but would also take a lot of work. Luckily, the PaperTrail gem works beautifully. By default it stores every create, update or destroy action and allows you to revert those changes - and you can create a revert action that your users can use, which you can then display in a flash message. Setup is surprisingly painless, and Railscasts has an excellent run-through of how to get it working.

Keyboard shortcuts

Keyboard shortcuts can make it much, much easier to use your app at speed. They make it easier for power users to get things done in split-seconds without getting in the way of new users.

Keyboard shortcuts that are simple and obvious are best. Here's an example from Submarine - when you add a contact, you can add notes, tasks or placements.

Keyboard shortcuts

Pressing "n" will add focus to the note input field, "t" to the new task and "p" to the placement form field. Of course, those shortcuts only work if you're not already focused on an input element (otherwise you wouldn't be able to write anything).

It also has command + alt + ... style shortcuts for things like adding a new contact, but I personally love the ease and simplicity of the single letter shortcuts.

How to do it

There are a few gems that help you to implement keyboard shortcuts for Rails, and I've heard good things about Mousetrap, but for Submarine I've been using Keymaster.js by Thomas Fuchs. It's lightweight and is remarkably easy to add to your Rails app. Once you've added keymaster.js to your JavaScripts assets folder, you can start defining your shortcuts. Here's how simple that "n" shortcut is:

key('n', function(){
  // Here's how I add focus to the note input
  return false;

And keyboard shortcuts that use multiple keys are also easy to add:

key('⌘+shift+p', function(){
  // the below simulates a click on a specified button

Autocomplete for form fields

For some situations, autocomplete can make life a lot easier. In Submarine, for example, when you add a contact you can also choose to (optionally) add their company name. Before it gets saved, it first checks to see if the company already exists - if it does, they're added as an employee of that company. If that company doesn't already exist, then it'll create a new company record.

There is an issue there though, as some people might list a contact as working for "Apple", while others might list them as working for "Apple, Inc", "Apple Computer" or any other variant. This is where autocomplete comes in. If the company record already exists, it'll pop up in autocomplete which helps to reduce the likelihood that a user will create a whole new record for a company that already exists.


How to do it

To get this working, all you need is jQuery UI's autocomplete function. This Railscast episode runs you through how to set it up to work with your Rails app.

Auto-populating form fields

Don't make users do any more work than is necessary.

In Submarine, you can assign a company (or create a new company) at the same time as adding a contact, in the same form, and there are form fields for the company name and the company website. If you add in the company name and it's a company that's already in the system, then Submarine already has that website address. There's no reason to make the user fill in that field again, so it saves them time by auto-populating it.

Autopopulating form fields

When they type "Apple" into the form field (assuming Apple and Apple's website is in their CRM), then "" will automatically appear in the website form field.

How to do it

The jQuery autocomplete function shown above also allows you to specify a function if the Company Name form field has changed or if one of the autocomplete results has been selected. Here's what it looks like in action:

  // Fetch the company names based on what's being typed into the field
  source: $('.autocomplete_company_name').data('autocomplete-source'),
// The select function is executed if a name is selected
  select: function( event, ui ) {
// These two lines make a request to Rails to get the company's website URL
    var cid = $('.campaign_id_hidden').data();
    $.getJSON("/campaigns/" + cid.campaign + "/autocomplete/" + ui.item.label, function(data) {
// The above is also repeated, but under the "Change" function to make sure it runs even if the user hasn't selected from the autocomplete dropdown
  change: function( event, ui ) {
    var cid = $('.campaign_id_hidden').data();
    var c_name = $('.autocomplete_company_name').val();
    $.getJSON("/campaigns/" + cid.campaign + "/autocomplete/" + c_name, function(data) {

The callback method is pretty simple - it just takes the website address that it's pulled from the data (if it's found one) and changes the value of the website form field to it. Here's what the code looks like:

function callback(data) {

The controller then has an action that looks like this (and has a before_filter to ensure that the user requesting it has access to that campaign):

def autocomplete_name
  @company = @campaign.companies.find_by_name(params[:name])
  render json: @company

Be lenient with data

Wherever possible, try to be lenient with how data is entered. As an example, when you enter a Twitter username for a contact into Submarine, the system needs to store it as just the username - e.g. "elonmusk".

But you can't rely on users to always enter it like that. Some people will enter "@elonmusk", while others might paste in the whole Twitter URL. For input fields, think about what users might use and adapt accordingly.

# In the contact.rb model
before_validation :clean_twitter_username

def clean_twitter_username
  if self.twitter.present?
    if self.twitter.include?("")
      self.twitter = self.twitter.gsub("", "")
    if self.twitter.include?("@")
      self.twitter = self.twitter.gsub("@", "")

This allows users to throw data into the app, and Submarine can do the heavy lifting instead of forcing the user to think about it.

If you want to pick up more tips on improving your app's UI, I'd recommend checking out, which has some great advice on things to watch out for.

Published March, 2014

Submarine CRM
Submarine is a CRM built for marketing & PR teams.
Click to find out more.