---
title: the more things change...
teaser: Including AJAX in Rails views.
tags: web,rails
author: Jared Carroll
published_on: 2007-07-23
---

Recently, like everyone else, we've been putting some <abbr title="Asynchronous
JavaScript And XML">AJAX</abbr> in our apps.

Now in Rails you have 2 ways to respond to <abbr title="Asynchronous JavaScript
And XML">AJAX</abbr> requests:

1. Send <abbr title="HyperText Markup Language">HTML</abbr> back to the client
   and let client side JavaScript (in the form of Rails helper methods) update
   the page with the response text.  This can be done by rendering partials
   without layouts in your controller actions.
1. Send JavaScript back to the client that gets executed automatically and
   contains the logic to update the page with the response text.  This can be
   done by rendering RJS views in your controller actions that will be converted
   to JavaScript before being sent back to the client.

I like either way but I found out that responding with JavaScript that the
client automatically executes results in some cleaner and simpler views.  Plus
using RJS, I can write my JavaScript in Ruby.  I like this since I've already
gotten used to writing my <abbr title="Structured Query Language">SQL</abbr> in
Ruby via migrations.

Let's take the simple example of an AJAXified form where the form to create a
new record is on the same page that lists all records, in other words on #index
there's a form that POSTs to #create.

Say in this app we're creating users that have nothing more than a name.

```ruby
class User < ActiveRecord::Base

  validates_presence_of :name

end
```

Schema:

    users (id, name)

Here's our controller:

```ruby
class UsersController < ApplicationController

  def create
    @user = User.new params[:user]
    respond_to do |wants|
      if @user.save
        wants.html { redirect_to users_path }
        wants.js
      else
        wants.html { render :action => :index }
        wants.js
      end
    end
  end

  def index
    @users = User.find :all
  end

end
```

In `create.rjs`:

```ruby
if @user.valid?
  page.insert_html :top, 'users', render(:partial => 'user',
                                         :object => @user)
  page[:errors].replace_html ''
  page[:users_form].reset
else
  page[:errors].replace_html error_messages_for(:user)
end
```

I don't like the fact that there's an 'if' in the action and in the `create.rjs`
template.  Now in the normal non-AJAX version of the #create action I just
render the #index action's view if the save fails so there's only 1 'if'.  2
'if's are necessary in the <abbr title="Asynchronous JavaScript And
XML">AJAX</abbr> version of the #create action because there's only 1 RJS view
used (technically there's only 1 view, `index.rhtml` used in the non-AJAX
version because its used for both success and failure).

I've also seen alternative implementations of #create like this:

```ruby
  class UsersController < ApplicationController

    def create
      @user = User.new(params[:user])
      @saved = @user.save
      respond_to do |wants|
        if @saved
          wants.html { redirect_to users_path }
          wants.js
        else
          wants.html { render :action => :index }
          wants.js
        end
      end
    end

    def index
      @users = User.find :all
    end

  end
```

In `create.rjs`:

```ruby
if @saved
  page.insert_html :top, 'users', render(:partial => 'user',
                                         :object => @user)
  page[:errors].replace_html ''
  page[:users_form].reset
else
  page[:errors].replace_html error_messages_for(:user)
end
```

This results in the same amount of 'if's but now we have this nice ugly boolean
flag instance variable telling us the success or failure of the #save call. In
my endless quest to remove all conditional logic from software, what I want is
another RJS view to handle the case in which the save fails, so I can get rid of
the 2nd 'if' in my `create.rjs` view.

Let's try:

```ruby
class UsersController < ApplicationController

  def create
    @user = User.new params[:user]
    respond_to do |wants|
      if @user.save
        wants.html { redirect_to users_path }
        wants.js
      else
        wants.html { render :action => :index }
        wants.js { render :action => :index }
      end
    end
  end

  def index
    @users = User.find :all
  end

end
```

In `index.rjs`:

```ruby
page[:errors].replace_html error_messages_for(:user)
```

In `create.rjs`:

```ruby
page.insert_html :top, 'users', render(:partial => 'user',
                                       :object => @user)
page[:errors].replace_html ''
page[:users_form].reset
```

What I added to UsersController#create is in the `else` branch:

```ruby
wants.js { render :action => :index }
```

However this is just going to respond back with `index.rhtml` and not respond
with `index.rjs` which has the RJS to display the errors on the page.

I thought maybe I could pass a :format parameter like:

```ruby
wants.js { render :action => :index, :format => :js }
```

But no, this didn't work either.

After some more trial and error I found out the following works:

```ruby
class UsersController < ApplicationController

  def create
    @user = User.new params[:user]
    respond_to do |wants|
      if @user.save
        wants.html { redirect_to users_path }
        wants.js
      else
        wants.html { render :action => :index }
        wants.js { render :action => 'index.rjs' }
      end
    end
  end

  def index
    @users = User.find :all
  end

end
```

I changed that same 1 line in UsersController#create this time to:

```ruby
wants.js { render :action => 'index.rjs' }
```

Now actions for handling both <abbr title="Asynchronous JavaScript And
XML">AJAX</abbr> and non-AJAX requests contain the same amount of conditional
logic and follow the same pattern.
