Ruby on Rails 4 AJAX Form Example
In this quick post I’ll share some code to submit a Ruby on Rails 4 model form via AJAX.
I created a new directory and added RVM files for Ruby version and gemset.
File: .ruby-version
ruby-2.1.0
File: .ruby-gemset
rails4ajax
Installed Rails gem
gem install rails
Created a new Rails project
rails new rails4ajax
Generated the complete scaffolding for a Model called “Thing”.
rails generate scaffold Thing title:string
Set up database (defaults to SQLite)
rake db:migrate
Added model validation, to test the ajax error response.
# file: app/models/thing.rb:
class Thing < ActiveRecord::Base
validates :title, presence: true
end
Revised the json format blocks for the update and create actions in the Things controller.
# file: app/controllers/things_controller.rb
@@ -29,10 +29,10 @@ class ThingsController < ApplicationController
respond_to do |format|
if @thing.save
format.html { redirect_to @thing, notice: 'Thing was successfully created.' }
- format.json { render action: 'show', status: :created, location: @thing }
+ format.json { render json: @thing }
else
format.html { render action: 'new' }
- format.json { render json: @thing.errors, status: :unprocessable_entity }
+ format.json { render json: @thing.errors.full_messages, status: :unprocessable_entity }
end
end
end
@@ -43,10 +43,10 @@ class ThingsController < ApplicationController
respond_to do |format|
if @thing.update(thing_params)
format.html { redirect_to @thing, notice: 'Thing was successfully updated.' }
- format.json { head :no_content }
+ format.json { render json: @thing }
else
format.html { render action: 'edit' }
- format.json { render json: @thing.errors, status: :unprocessable_entity }
+ format.json { render json: @thing.errors.full_messages, status: :unprocessable_entity }
end
end
end
Revised the form, modified the form_for tag and error container html
# file: app/views/things/_form.html.erb
<%= form_for(@thing, remote: true, format: :json, html: {class: :thing_form}) do |f| %>
<div id="error_explanation" style='display:none;'>
<ul>
<% if @thing.errors.any? %>
<% @thing.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
</ul>
</div>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Added AJAX listeners (coffeescript)
# file: app/assets/javascripts/things.js.coffee
$(document).ready ->
$(document).bind "ajaxSuccess", "form.thing_form", (event, xhr, settings) ->
$thing_form = $(event.data)
$error_container = $("#error_explanation", $thing_form)
$error_container_ul = $("ul", $error_container)
$("<p>").html(xhr.responseJSON.title + " saved.").appendTo $thing_form
if $("li", $error_container_ul).length
$("li", $error_container_ul).remove()
$error_container.hide()
$(document).bind "ajaxError", "form.thing_form", (event, jqxhr, settings, exception) ->
$thing_form = $(event.data)
$error_container = $("#error_explanation", $thing_form)
$error_container_ul = $("ul", $error_container)
$error_container.show() if $error_container.is(":hidden")
$.each jqxhr.responseJSON, (index, message) ->
$("<li>").html(message).appendTo $error_container_ul
I started the server via “rails s”, and browsed to the url: http://localhost:3000/things/new
Submitting the form without entering a title will show the errors container. Submitting with a title will hide the errors and display a message that the Thing was saved.