Sep 29, 2009

If your Rails app requires cookies, this recipe is for you: It detects whether cookies are enabled, and if not, shows a message to your users.

This recipe checks for the presence of a specific cookie (“cookie_test”). If it is present, the request continues normally. If it is not present, then it sets the cookie, redirects to the “cookie_test” action and checks there whether the cookie is present. If the cookie is present, then everything continues on normally. If the cookie is still not present, then this is a strong indication that the user has cookies disabled. Then the recipe shows a page to the user explaining the cookie requirement. I leave it up to you to write the copy for that page.

Flow chart for the cookie detection recipe

Flow chart for the cookie detection recipe

This recipe works as of Rails 2.3 (new cookie handling). It is inspired by this article. The recipe in the original article does not work with newer versions of rails. So I updated it and packaged it up in a neat little module that you can include in your application controller.

How to use it

  1. save this file at a location in your rails app where it gets required (e.g. RAILS_ROOT/lib/cookie_detection.rb)
  2. In application_controller.rb:
    Include CookieDetection (at the top to make this the first before_filter)
  3. In routes.rb:
    map.cookies_test “cookie_test”, :controller => “application”, :action => “cookie_test”
  4. In RAILS_ROOT/views/shared/cookies_required.html.erb:
    Display a message that lets your users know of the cookie requirement.
# RAILS_ROOT/lib/cookie_detection.rb

# Detects if cookies are present.
# If cookies are disabled, shows view located at shared/cookies_required
# Usage:
# * save this file at a location in your rails app where it gets required
#   (e.g. RAILS_ROOT/lib)
# * application_controller:
#   Include CookieDetection (at the top to make this the first before_filter)
# * routes.rb:
#   map.cookies_test "cookie_test", :controller => "application", :action => "cookie_test"
# * views/shared/cookies_required.html.erb:
#   Display a message that lets your users know of the cookie requirement.
module CookieDetection

  def self.included(base)
    base.before_filter :cookies_required, :except => ["cookie_test"]
  end

  # checks for presence of "cookie_test" cookie
  # (should have been set by cookies_required before_filter)
  # if cookie is present, continue normal operation
  # otherwise show cookie warning at "shared/cookies_required"
  def cookie_test
    if cookies["cookie_test"].blank?
      logger.warn("=== cookies are disabled")
      render :template => "shared/cookies_required", :layout => "system"
    else
      redirect_back_or_default(dashboard_path)
    end
  end

protected

  # checks for presence of "cookie_test" cookie.
  # If not present, redirects to cookies_test action
  def cookies_required
    return true unless cookies["cookie_test"].blank?
    cookies["cookie_test"] = Time.now
    session[:return_to] = request.request_uri
    redirect_to(cookies_test_path)
  end

end