A few weeks ago, I started building this Rails app to help me become a better writer. It’s a simple app that is meant to motivate me to write every day by keeping track of streaks and awards points based on number of words written.

When I first began building the writing interface in the app, I wanted to make it easy to save my work, and decided that a Google docs style autosave feature would work well. With jQuery and AJAX, it’s really simple.

First, I have a view template for the writing page:

.saved
  Saved
  = @post_today.updated_at.strftime("%l:%M:%S%P")

%article.writing-area
  %textarea.col-sm-6
    = @post_today.content

This doesn’t actually use a full fledged form to update the model, since we’ll be saving the model in the background via AJAX. All it has is a text area that contains the post as it was last updated, so I can continue writing if I had already started the post.

In order to update the post in the background, I used a simple Javascript function to submit the contents of the textarea.

function autoSave() {
  var content = $("textarea").val();
  $.post('/update_post', {content: content})
}

setInterval(autoSave, 10000);

$.post is just a wrapper around jQuery’s $.ajax function that shortens the amount of code you have to write in order to send a post request.

The piece that’s really important is setInterval. It takes two arguments: a function, and time in milliseconds. In the above example, setInterval will run autoSave every ten seconds. Note that I don’t pass in autoSave with parentheses like you would when calling a regular function. This is because the function needs to be passed in as a piece of data to be used by setInterval. If I had passed in autoSave(), it would have returned the value of the function once and exited.

The request is sent with the parameters as a Javascript object, and gets sent to the controller just like any form submission would.

  class PostsController < ApplicationController
    def update
      @post = current_user.posts.today
      
      # If nothing has been written, don't update the model
      return if params[:content].nil?
      
      @post.update_attribute(:content, params[:content])

      respond_to do |format|
        format.js
      end
    end
  end

When the post is saved, it renders Javascript back to the browser:

  $(".saved").html("Saved <%= Time.now.strftime('%l:%M:%S%P') %>")

This notifies the user that their post saved by changing the time it was last updated:

saved

There isn’t much to it, and it’s a really simple way to improve your user experience.