A Discussion on Ajax

Motivation

Shortly after writing this I uploaded a series of posts in which I walked through how to build a real-world database-backed contact form in a Ruby on Rails web application. The form was contained within a partial view that was rendered from a larger view (think of a contact form at the bottom of a home page).

In addition to many other capabilities, the form can:

  1. Display help text after both successful and unsuccessful submissions, and
  2. Reset all fields upon submission

The catch is that I wanted this to be possible without causing the larger view to reload after each form submission. In order to build this, I needed to use asynchronous JavaScript and XML, otherwise known as Ajax.

It took me an excruciatingly long time to figure out how to build my contact form with Ajax. While searching for a solution I often found instructions to simply add remote: true to my <%=form_for...%>...<%end%> code block within my partial view, and then to wave around some JavaScript magic. I plugged away for days and NOTHING worked. It was a nightmare.

I finally figured out that I first needed to take a step back and understand Rails forms built with Ajax from a high level before trying to incorporate Ajax-related code into my application. Videos by Ryan Bates and Sagar Shah helped me tremendously in understanding the theory behind how Ajax works in a Rails form.

The Theory

By default Rails renders both full and partial views that are written in an html format (think of views named [view].html.erb or _[partialview].html.erb). Rendering an html view requires a full-page reload. However, Rails has built-in Ajax capabilities that allow for the rendering of partial views written in a JavaScript format. JavaScript partial views are named [view].js.erb, and they can interact with html views.

This matters because JavaScript partial views can respond to user actions by changing the objects inside an html view WITHOUT requiring the affected html view to reload.

Let’s look at a filled-out form as an example. Before the user hits “submit”, it will look something like this:

completed form_2

An Aside on Assumptions

Let’s assume that to build the form shown above we first created a model named Message. Let’s also assume that this form is coded inside a partial view (named, for example, _form.html.erb) and saved in MyAppName/app/views/messages. The embedded Ruby code written inside the partial view, which generates the above form, would look something like this:

<%= form_for @message ... do |f| %>
...
<%= f.submit "Submit" %>
<% end %>

Next let’s assume that the controller (named Pages in this example) that provides the main view to the browser (i.e. the “home” page view, named index.html.erb) contains the following code:

class PagesController < ApplicationController
def index
@message = Message.new
end
end

And, let’s assume that the Messages controller responsible for the _form.html.erb partial view (rendered by the Pages controller’s index.html.erb view) contains the following code:

class MessagesController < ApplicationController
def create
@message = Message.new(message_params)
...
end
end

The final assumption is that the routes.rb file saved in MyAppName/config contains the following code:

get ‘messages/new' => ‘messages#new'
post ‘messages’ => ‘messages#create’

These assumptions are important because they clarify that pressing “Submit” on the form in the above example sends an HTTP POST request to the Messages table in the database. (Actually, the Rails form_for helper generates an html form that submits HTTP POST requests by default, but we needed to specify which database table the form will modify.) An HTTP POST request is mapped to the Rails create action. To learn more about how HTTP verbs are mapped to controller actions, click here.

Back to the Theory

Let’s take another look at the filled-out form example that we started with now that I’ve clarified that pressing “Submit” triggers the Messages controller’s create action. By default, the create action tells Rails to search for an html view to render. Ajax changes this default behavior so that the create action tells Rails to search for a JavaScript partial view (which will then interact with the already-rendered _form.html.erb partial view.)

Then, the code inside the JavaScript partial view should contain instructions for both resetting the two form input fields and displaying help text below the form, as shown in this picture:

form help text_3

This means that after building Ajax into a form, we need to do two more things:

  1. Call a JavaScript partial view from the Messages controller’s create action, and
  2. Build the actual JavaScript partial view

Enough Theory – Tell Me How to build AJAX into my Form!

Step 1: Add ‘remote: true’ to the Rails Form Helper
Building an Ajax form is straightforward with the Rails form_for helper. Simply add remote: true.

<%= form_for @message, remote: true do |f| %>
...
<%= f.submit "Submit" %>
<% end %>

Step 2: Add respond_to to the Controller
Now that Rails will search for a JavaScript partial view as part of the create action, we need to tell the Rails controller where to find this JavaScript partial view. Do this by adding a respond_to do |format| block into the messages_controller.rb file saved in MyAppName/app/controllers.

The general structure of the respond_to do |format| block is as follows:

class MessagesController < ApplicationController
def create
@message = Message.new(message_params)
respond to do |format|
format.js
end
end
end

Step 3: Create the create.js.erb View
Finally, open a blank text file and write all of the jQuery, JavaScript, and Ruby code that displays error and success messages, and that also resets the form. Name the file create.js.erb and save it to the MyAppName/app/views/messages folder.

Note: The file’s name is create because it needs to have the same name as the Rails action that calls the JavaScript partial view.

Wrap Up

A pattern I ran into while searching online for how to submit a Rails form with Ajax was that each example I found walked through a scenario that was slightly different from what I was trying to achieve. Since I didn’t understand the theory behind Ajax forms in Rails, I wasn’t able to modify the examples I found to suit my needs. Thus, I didn’t go into too many specifics in this post because my goal was to give a high-level overview of how to implement Ajax in a Rails form.

If you are interested in specifics, check out my post series that covers all of the steps needed to build a “real-world” database-backed contact form in a Ruby on Rails application.

 

Did you find this walkthrough helpful?

Do you have questions on the above?

Do you see any errors?

 

If so, please leave your thoughts in the comments below.