Using HTTP Status Codes for Rails AJAX Error Handling

A problem that often arises in AJAX-based web applications is how to handle it when things go wrong. The user should be informed of the problem in a descriptive manner, but obviously the internal workings of the application should not be revealed. A generic and useful way to handle this problem is to use HTTP Status Codes to indicate the type of failure, and use the javascript to cope appropriately.

In this example I will be using jQuery, but the principles behind are just as applicable to Prototype or any other Javascript library.

Your Friends 403 and 500

Anyone who’s built a Rails site is familiar with the 500 error. That’s the generic exception code thrown whenever something goes wrong in your application. Users should, hopefully, never ever see this when they’re using the site. However, oftentimes there are exceptions or errors that users should experience just as result of improperly filling out fields, permissioning, etc. So how do we differentiate?

The Rails render method has the ability to render out an arbitrary HTTP Status Code (i.e. 500 for error, 404 for not found, and many more). The “403 Forbidden” code means that the server understood the request made of it, but is refusing to complete it. This sounds like an apt description for typically “caught” exceptions. So let’s use the 403 code to intelligently handle the exceptions that we want to be seen by the user.

In the controller

Let’s take the simplest example, an invalid record. If you are creating a record via AJAX, a flash[:error] with a render :action => "new" is not going to suffice. Let’s try something like this instead:

class ItemsController < ApplicationController
  def create
    Item.create!(params[:item])
    # continue on your merry way if it works
  rescue ActiveRecord::RecordInvalid => e
    respond_to do |format|
      format.html { 
        flash.now[:error] = "There was a problem creating the item." 
        render :action => "new" 
      }
      # Render out the validation failed message with a
      # 403 status code.
      format.js { render :text => e.message, :status => 403 }
    end
  end
end

All right, now that we’ve got it handled on the controller side, it’s time to work some Javascript magic on our AJAX call.


$('a#ajax_link').click(function() {
  $.ajax({
    url: '/items', 
    success:function(data, textStatus) {
      // do success things
    },
    error:function(request, textStatus, errorThrown) {
      // Use the specific message for a 403, but
      // a generic failure message for a 500
      var message = (request.status == 403) ? 
        request.responseText : "An unknown error occurred. Support has been contacted.";
      // Simple alert for example, but you can handle
      // however you want, such as populating an error message
      // div and making it appear.
      alert(message);
    }
    return false;
  });
});

Now when your AJAX request fails, it will render a user-friendly error message if it’s an ‘expected’ error or a generic message if the request fails with an unexpected exception.

This is a simple example, but by building a general framework for error expectations you can make it much easier to provide user-friendly error handling that gives them all of the information they need without revealing any of your internal processes.

Share:

Comment on this post (0 comments)


Mobilize Your Rails Application with Mobile Fu

Let's face it, iPhone interfaces are awesome, but they can only cater to a fraction of the mobile market. What are you to do if you want to satisfy the rest of the mobile world? Mobile Fu helps to make this job much easier by automatically detecting mobile devices that access your Rails application. People can access your site from a Palm, Blackberry, iPhone, Nokia, etc. and it will automatically adjust the format of the request from :html to :mobile.

Learn Mobile Fu

First off, just install the Mobile Fu plugin into your Rails application.

script/plugin install git://github.com/brendanlim/mobile-fu.git 

Start by adding this one line to your ApplicationController.

class ApplicationController < ActionController::Base
  has_mobile_fu
end

Once this is in place, any request that comes from a mobile device will be be set as :mobile format. It is up to you to determine how you want to handle these requests by creating the .mobile.erb versions of your views that are to be requested. Also, I recommend that you setup a before_filter that will redirect to a specific page depending on whether or not it is a mobile request. How can you check this?

is_mobile_device? # => Returns true or false depending on the device

You can also determine which format is currently set in by calling the method below.

is_mobile_view? # => Returns true or false depending on current req. format

If you want the ability to allow a user to switch between ‘mobile’ and ‘standard’ format (:html), you can just adjust the mobile_view session variable in a custom controller action.

session[:mobile_view] # => Set to true if request format is :mobile and false
                           if set to :html

What About Custom Mobile Styling?

Different devices need different styling. Don’t worry though, we’ve got this baked in to Mobile Fu (thanks to Intridea's own Michael Bleigh, who created Browserized Styles for letting me modify his code). If you are including a css or sass file via stylesheet_link_tag, all you have to do is add _device to the name of one of your files to override your styling for a certain device. The stylesheet that is loaded is dependant on which device is making the request.

Supported stylesheet override device extensions at the moment are: blackberry, iphone, mobileexplorer, nokia, palm

e.g., Accessing a page from a Blackberry.

<%= stylesheet_link_tag 'mobile.css' %>  

Ends up loading mobile.css, and mobile_blackberry.css if the file exists.

Feature Requests

You can check out Mobile Fu's very own project page at Acts As Community. If you have any problems or would like me to add a certain feature, please create a ticket at http://blim.lighthouseapp.com/projects/14490-mobile-fu/. Also, feel free to fork Mobile Fu and make any enhancements you please from its GitHub location at: http://github.com/brendanlim/mobile-fu/tree/master

Share:

Comment on this post (0 comments)


UberKit Update: UberForms To Ease Form Building

Last week the Uberkit kicked off with some helpers to make your menu-building much easier. This week we’re following it up with UberForms, a Form Builder that DRYs up your repetitive form stresses. Let’s see how it works!

Building an Uber-er Form

UberForms automatically generate all of the standard boilerplate HTML that goes around your forms. By wrapping everything up in an easily style-able package, it becomes a much easier business to make new forms as well as re-use form styling across projects. With the form markup taken care of, you can focus on the more important aspects of your UI building and keep your views deadly clean.

While UberForms are available as a standard form builder (Uberkit::Forms::Builder), you may find it more useful in its helper form (automatically available when the UberKit plugin is loaded:

<% uberform_for :user do |f| %>
  <%= f.text_field :login %>
  <%= f.password_field :password %>
  <%= f.submit "Submit"%>
<% end %>

This will automatically be translated into some nice, CSS-ready HTML:

<form method="post" class="uberform" action="/users">
  <div class="field_row">
    <label for="user_login">Login:</label>
    <input type="text" size="30" name="user[login]" id="user_login" class="text_field"/>
    <br/>
  </div>
  <div class="field_row">
    <label for="user_password">Password:</label>
    <input type="password" size="30" name="user[password]" id="user_password" class="password_field"/>
    <br/>
  </div>
  <button type="submit">Submit</button>
</form>

You can also change the label, add a description or help text to a field by adding the relevant options:

<%= f.text_field :login, :label => "Username", 
                         :help => "Only a-z and underscores.", 
                         :description => "The name you will use to log in." %>

Becomes…

<div class="field_row">
  <label for="user_login">Username:</label>
  <input type="text" size="30" name="user[login]" label="Username" id="user_login" help="Only a-z and underscores." description="The name you will use to log in." class="text_field"/>
  <span class="help">Only a-z and underscores.</span>
  <span class="description">The name you will use to log in.</span>
  <br/>
</div>

Finally, you can create custom HTML inside an UberForm field by passing a block:

<% f.custom :label => "State", :for => "user_state" do |f| %>
  <%= state_select :user, :state %>
<% end %>

Becomes…

<div class="field_row">
  <label for="user_state">State:</label>
  <div class="pseudo_field">
    <select id="user_state">...</select>
  </div> 
  <br/>
</div>

Easy, right? That’s all there is to it, now you can be UberForming to your heart’s content

Installation

To install the UberKit (which includes more than just forms) you can do so either as a gem or a traditional plugin. As a gem, just add this to your environment.rb:

config.gem 'mbleigh-uberkit', :lib => 'uberkit', :source => 'http://gems.github.com'

As a traditional Rails plugin:

script/plugin install git://github.com/mbleigh/uberkit.git

The Future of the UberKit

These two pieces are pretty helpful, but there’s more coming for the UberKit. Stay tuned for more updates, including more hooks and ways to customize the UberKit to fit your needs as a developer.

Share:

Comment on this post (0 comments)


iPhone 3G Released Today - iHysteria Ensues

Posted by on July 11th, 2008.

Ever since it's announcement at WWDC 2008, most of us have been waiting anxiously to get our hands on the new iPhone 3G. If you haven't been keeping up with the news or have just been in a coma for the past few weeks, you'd know that the second coming of the iPhone was to be released today at Apple and AT&T stores nationwide.



I arrived at the Apple Store at Lenox Mall in Atlanta, GA around five in the morning and ended up being the fifth person in line. Quite surprising, since the Apple Store in New York City had people lining up since last week. After purchasing and activating my new iPhone 3G, I had a chance to play with all of its great new features.

The first thing you'll notice is that the once silver backing has been replaced with a shiny, plastic back. The 8GB iPhone 3G ($199) only comes in black, whereas the 16GB iPhone 3G ($299) comes in either black or white. Surprisingly, the new plastic back, which has a nice curve to it, feels high quality and fits very nicely in your hand. My only gripe though, is that the black color is very prone to smudges and finger prints. Metal has replaced the old plastic volume, power, and silence switch, which also add to a sturdier feel. The recessed-headphone jack is also now no more, allowing you to ditch the clunky adapters that were needed for the first generation iPhone. Also, the chrome bezel around the edges has been pushed back, which gives off the impression that the face is larger, even though the front dimensions are exactly the same as the previous generation.

So, the iPhone 3G is named the way it is for a reason. Finally, you can get 3G speeds on AT&T's HSDPA network, which blows EDGE out of the water. I've gotten accustomed to EDGE speeds over the past year and having pages load up to 2.4x faster is a luxury I don't ever want to live without again. Now I can browse all of my favorite sites without spending so much time waiting for everything to load.



If you had a first generation iPhone, you probably didn't use the speakerphone that much because it was quite worthless. It's now quite loud. The much louder volume of the speakerphone is definitely something that I am very happy about. Now, I can hear my calls loud (very) and clear. Speaking of clarity, many have said that the incoming and outgoing voice quality has been vastly improved. I've noticed a much cleaner, crisper sound while on the phone, but nothing dramatic.


One of the coolest new features is the GPS capability. You now get 'real' GPS, unlike the cellphone tower triangulation that was used in the previous generation iPhone. You don't get voice guided, turn by turn directions out of the box, but it's really neat to see that blue, pulsating dot, smoothly move through the map, showing you exactly where you are. I had a fun time using it on the way back home from the Apple Store. It's also been confirmed that Navigon, will be producing a third-party app, available in the App Store sometime soon, that will provide real turn-by-turn navigation.



Speaking of third party applications, this is really where the new 2.0 firmware shines. The App Store allows you to purchase either paid-for or free applications, right from your new iPhone 3G. There are over 500 different applications already available during launch time. The majority of the applications now are not free, but the average price per application seems to fall between $5 and $10.

Also, anybody can develop these applications with the iPhone SDK. As the developer, you can take advantage of Multi-Touch interface, the accelerometer, GPS, real-time 3D graphics, and 3D positional audio to create some amazing applications. You can also choose to let your product be downloaded for free or you can charge a price. If you decide to charge a price, you agree to pay Apple 30% of the final purchase price. The App Store is proving itself to be a great place for developers to get their products directly to the consumer which an amazing amount of ease.



There are many other great features with the 2.0 firmware that I haven't mentioned, push integration with Exchange and MobileMe, bug fixes, and much more - to list them all, would take quite some time. The iPhone 3G is a nice upgrade from the original iPhone, and if you haven't gotten an iPhone yet, the lowered price and the great new features make it an amazing deal. Look out for some great iPhone applications from us in the future.

Share:

Comment on this post (0 comments)


UberKit: Building A Rails UI Swiss-Army Knife

So many of components we build into our web applications have a grain of an extractable element, a standardization waiting to happen. Starting today, I am putting together a “Standard UI Kit” for all of the tools that help me build interfaces faster. Together, they are called the UberKit. This week, the first segment is coming: UberMenus.

UberMenu: Abstract Menu Generation

Most people who build interfaces will build their menus with the same structure over and over. I finally took the time to abstract this out into a single helper that can pretty much serve all of my navigational needs. Here’s how you use it in a view:

<% ubermenu do |m| %>
  <% m.action 'Home', '/' %>
  <% m.action 'Users', users_path %>
  <% m.action 'Log Out', logout_path, :class => "special" %>
<% end %>

Becomes this HTML (assuming you’re at the document root):

<ul>
  <li class="first current first_current"><a href="/">Home</a></li>
  <li><a href="/users">Users</a></li>
  <li class="special last"><a href="/logout">Log Out</a></li>
</ul>

The current class will automatically be set on whichever page responds to the built-in Rails helper current_page? and the action syntax behaves just like a link_to. If a given action has multiple classes, they will also be joined with underscores as an additional class for browsers that do not support multiple class declarations. But in addition to easily creating simple menus, you can also easily generate multi-level navigation menus:

<% ubermenu 'nav' do |m| %>
  <% m.action 'Home', home_path %>
  <% m.submenu 'Services', services_path do |s| %>
    <% s.action 'Service A', service_path('a') %>
    <% s.action 'Service B', service_path('b') %>
  <% end %>
<% end %>

Which will become this HTML:

<ul id='nav'>
  <li class='first current first_current'><a href="/">Home</a></li>
  <li class='last'><a href="/services">Services</a>
    <ul>
      <li><a href="/services/a">Service A</a></li>
      <li><a href="/services/b">Service B</a></li>
    </ul>
  </li>
</ul>

Installation

UberKit is available both as a gem and a traditional plugin. For the gem version, add this to your environment.rb:

config.gem 'mbleigh-uberkit', :source => "http://gems.github.com/", :lib => "uberkit"

Or as a traditional plugin:

script/plugin install git://github.com/mbleigh/uberkit.git

Future of the UberKit

While UberMenu is a useful tool, the UberKit will continue to grow over time, so stay tuned for additions (next on the slate: UberForm). It may also grow to include some common styles and javascripts that can be used in conjunction with the helpers to provide an even easier track to a full-fledged UI.

Resources

As always, the source is on GitHub and there is an Acts As Community Profile available as well. If you have any problems with it or would like to request new features, enter them on the Lighthouse project.

Share:

Comment on this post (1 comment)