When building a web application, it's desirable to serve cached pages from memory or a CDN as frequently as possible to reduce load on the origin server. However, this becomes more complicated when rendered content varies for each user of an application. Fragment caching alleviates some of these woes but often performs less efficiently than caching entire pages and rendering custom fragments dynamically.

In the case of a Rails application, a developer might choose to cache an entire controller action to serve content from memory rather executing the action each time a request is passed to it. While action caching performs better than its fragmented counterpart, it leaves the developer unable to render personalized content to a cached page without using JavaScript.

Here, I'll demonstrate a simple method that can be used to handle Rails flash messages while still taking full advantage of action caching or page caching with a CDN.

Store flash messages to a cookie

In order to dynamically render flash messages, they can be serialized and stored to a cookie.

Messages set in flash will be available after a redirect while those stored in flash.now are only available throughout the lifetime of the current controller action. Messages from both hashes should be extracted, and the hash should be cleared after storage to a cookie to avoid rendering messages more than once.

def move_flash_to_cookie
  if !flash.empty?
    now_hash = flash.now.flash.to_hash
    messages = flash.to_hash.merge(now_hash).select{ |_, v| v.present? }
    cookies[:flash_messages] = JSON.generate(messages)
    flash.clear
  end
end

It'd be ideal to store flash messages to a cookie using an after_filter, but those messages wouldn't be available in the view due to render being called prior to completion of the controller action. To work around this, override the redirect_to and render methods in the ApplicationController.

def redirect_to(*args)
  move_flash_to_cookie
  super
end

def render(*args)
  move_flash_to_cookie
  super
end

Now, flash messages will be stored to a cookie prior to redirecting the user or rendering the view for any controller action in the application.

Define a JavaScript function to handle messages from the cookie

Once a flash message is stored to a cookie, it can be handled using JavaScript. Rather than polling for messages, I want to explicitly check for them in my application. If the cookie exists, the check function will deserialize the JSON object in the cookie and iterate through each type of flash message to allow each to be handled independently. Once all messages have been handled, the cookie is deleted to prevent duplicate handling of messages.

Note: I use the jquery-cookie plugin for handling cookies.

class FlashMessage
  @check: ->
    cookieName = 'flash_messages'
    cookie = $.cookie(cookieName)
    if cookie?
      flashMessages = JSON.parse(cookie)
      for type, message of flashMessages
        @handle(type, message)
      $.removeCookie(cookieName, path: '/')

  @handle: (type, message) ->
    switch type
      when 'alert'
        # Handle an alert message
      when 'error'
        # Handle a warning message
      when 'notice'
        # Handle a notice message
      when 'custom'
        # Handle a custom message

Check for flash messages within application views

Suppose a user submits a form with invalid inputs. In Rails, it's common to store an error message to the flash, redirect the user to the form, and render the error message.

It's possible to mimic that pattern with JavaScript by checking for the flash message when rendering the form. Just add check() to the bottom of the view.

<script>
  FlashMessage.check()
</script>

When a user submits a bad form, the error message will be added to the flash_messages cookie, the user will be redirected to the form, and the snippet above will cause the message to be dynamically rendered.

There are a variety of other methods that can be used for handling dynamic content on cached pages - especially if you're building single-page applications with a framework like Ember.js. However, this method can be used when working with an application that's entirely handled with Rails or another server-side framework.

Happy caching!


I've used many todo lists and project management applications throughout the years, but a clear winner has emerged for organizing all the lists in my life. From designing software at Harvest to managing my grocery list, Asana provides a perfect blend of ease, flexibility, and mobility for "life management". I'd like to share some of the ways I use Asana in my life and hopefully inspire some ways that you can use it in yours.

Read more...


I'm always looking for ways to streamline my workflow, reduce clutter, and eliminate distractions. I've been effective in this quest throughout recent years, but I find myself paying more attention to email than is preferable. There are plenty of messages that can wait until the end of the day. However, others demand a more immediate response. Perhaps there's a pull request that needs my review or a new issue that's been assigned to me in Kaizen or Zendesk. Many of these can also wait, but wouldn't it be great to address them without introducing the unnecessary distractions that accompany the routine checking of email?

Read more...


Harvest It's hard to believe that I've been at Harvest for a month, but time flies when life is good. Looking back on my first four weeks has provided me with some insights about why my experience has been so enjoyable. I want to share a few of them as a pat on the back to my teammates and also as inspiration for other companies. Happy employees are productive employees!

Read more...


The iPad 3 is here! If you were lucky enough to snag one of these cool, new gadgets last week, you're now viewing your email, news, ebooks, and videos on a high-resolution retina display. Consumption never looked so good!

But there's one feature Tim Cook didn't share during the keynote. Yes, that's right. You've just adopted a shiny, new form of distraction. Congratulations!

Full disclosure: I own a MacBook Pro, iPad 2, and iPhone 4S. I'm among you.

Thursday's release served as a gentle reminder that it is far too easy to connect to the outside world these days. I won't argue against the usefulness of mobile devices, but I will share a few tips that have worked well when trying to clear my mental runways of debris.

Read more...


Over the past few days, I've developed an addiction with the self-tracking movement and have begun brainstorming various metrics that I'd like to start monitoring at a more granular level. These brainstorm sessions have generated an exceptionally long list, so I'm limiting myself for now until I'm able to optimize my methods.

Read more...


Jekyll

In recent years, social media like Twitter and Facebook have allowed me to communicate my ideas in small, palatable bites of information. This format was revolutionary (no pun intended) for the conflicts in Egypt and Iran, and it's allowed me to bitch about traffic and my university with stunning efficiency. Though, there are still times when I'd like to convey a longer or more complex message to the handful of people that might stumble upon my web presence. While Tumblr has served as a happy medium for some, I don't feel that we've fully eluded the need for traditional, robust blogging platforms like WordPress and TypePad.

Read more...


With another school semester on the horizon, I've been reviewing old course material to refresh my memory. Since a lot of this material is useful when devising algorithms, I'm going to spend the next few weeks revisiting some of the more interesting concepts. First up is the Fibonacci sequence. This is the sequence F(n) = F(n-2) + F(n-1) where F(0) = 0 and F(1) = 1.

If we wish to determine a given Fibonacci number n, there are several approaches we can take. The approaches I'll cover here involve recursion, iteration, Binet's formula, and matrix form. Each of the following examples assumes that the algorithm is handling a positive integer, and all were validated with Ruby 1.8.7.

Read more...


Collexion Just as Newton and Leibniz contributed separately to the development of differential and integral calculus, the brilliant minds at Collexion began planning their first Jelly not long before I expressed the need for one in my recent article. Buildycrunken will cater to software developers, writers, artists, students, and anyone else that desires to spend his or her late nights surrounded by creative, entertaining individuals. The first event will start at 9:00pm on November 6 and last until 9:00am the following morning, posing a challenge to those passionate about their work to gauge the limits of that passion with sleep deprivation and unhealthy quantities of caffeine. For those interested in attending, the madness will begin at Third Street Stuff at 9:00pm on November 6. I hope to see you there!


Jelly Since I started working at Awesome Inc. in June, I've fallen in love with the concept of creative individuals coming together within a single coworking space to share ideas and collaborate on projects. Our particular environment contains a coworking space, art studio, engineering workshop, and dance studio, and each component provides a unique contribution to the space's creative vibe. However, this style of workspace has its pitfalls, as many creative, independent professionals are reluctant to invest the money required to experience working in such an environment. While not founded for this particular purpose, Jelly provides an intermediate solution to those professionals wishing to transcend the boundaries of home offices and coffee shops without shelling out the fee associated with most coworking environments.

Read more...