1 0 Tag Archives: rails
post icon

Handling Validation Errors using Ajax Requests in Rails

After spending about 6 hours reserching how to handle errors when using ajax requests to create, update and do other actions in Ruby on Rails I got fed up and started doing it on my own, with a little help from Agile Web Development with Rails.

I spent countless hours looking through google and found nothing I liked, and this is why I’m writing this post. I also found nothing that showed all the code, from view to controller to js. So I’ll try and include everything here.

First background on what I wanted to do… I have an index.html.erb file that loops through an object that contains a bunch of stuff. What I wanted was:

  1. Have a form_remote_for at the bottom of this list that would do an Ajax.Request
  2. Have the new form values save to the database
  3. Print the new data to the bottom of the current list
  4. And handle any errors so the user would know wtf was going on

Ryan Bates has a sweet railscast screencast showing how to implement… well everything except the error handling. I’m just going to make it really simple just so you get an idea.

My index.html.erb file:

<table id="teams">
 <tr>
  <th>Team name</th>
  <% if logged_in? -%>
   <th>Action</th>
  <% end -%>
  </tr>
  <% for @team in @teams -%>
   <tr>
    <td><%= link_to @team.name, league_team_path(@league.id, @team.id) %></td>
    <% if logged_in? -%>
     <td>
      <%= link_to_remote image_tag('file_remove.png'), :url => team_path(@team.id), :method => :delete, :confirm => "Are you sure?" %>
      <%= link_to image_tag('file_edit.png'), edit_team_path(@team.id) %>
     </td>
    <% end -%>
   </tr>
  <% end -%>
</table>
<% if logged_in? -%>
 <div class="ajax_form">
  <% form_remote_for :team, :url => teams_path do |f| -%>
   <p id="team_name_para">
    <label id="team_name_label" for="team_name">Team name:</label>
    <%= f.text_field :name, :class => "large_set_width", :value => "" %>
    <button class="form_submit" type="submit"><span>Save</span></button>
   </p>
  <% end -%>
 </div>
<% end -%>

This is pretty basic, I just loop through all teams and print them out into a table with admin actions to edit and delete. Then the form_remote_for at the bottom that sends an Ajax.Request

My teams_controller.rb create action:

def create
 @team = @league.teams.build(params[:team])
 if @team.save
  respond_to do |format|
   flash[:notice] = @team.name + ' was successfully created.'
   format.html { redirect_to teams_path(@team) }
   format.js {
    render :update do |page|
     page.insert_html :bottom, :teams, :partial => "partials/assets/team", :object => @team
     page.replace_html :notice, "<p>"+flash[:notice]+"</p>"
     page.show 'notice'
     page.visual_effect :highlight, 'notice'
    end
   }
  end
 else
  respond_to do |format|
   format.html { render :action => "new" }
   format.js {
    render :update do |page|
     page.visual_effect :shake, "team_name_para"
     page.replace_html :team_name_label, @team.errors.full_messages
     page << "$('team_name_para').addClassName('form_error_message');"
    end
   }
  end
 end
end

This is pretty basic as well, we have the usual if @team.save and the html format in the respond to. What you want to look at is the format.js block. Instead of rendering a rjs file, were just going to take care of everything right in the controller. The first page.insert_html inserts the content from the team partial that gets the @team object passed to it. Partial looks like this:

<tr>
 <td><%= link_to @team.name, team_path(@team.id) %></td>
 <% if logged_in? -%>
  <td>
   <%= link_to_remote image_tag('file_remove.png'), :url => team_path(@team.id), :method => :delete, :confirm => "Are you sure?" %>
   <%= link_to image_tag('file_edit.png'), edit_league_team_path(@league.id, @team.id) %>
  </td>
 <% end -%>
</tr>

So basically that just renders to the bottom of the table… Then the next 3 just handle the flash[:notice]. I put in some scriptaculous goodness as well. One issue I had was the flash[:notice]. In my application.html.erb layout I had:

<% if flash[:notice] -%>
 <div id="notice">
  <%= flash[:notice] %>
 </div>
<% end -%>

But this wasn’t going to work with the page.replace_html :notice because the div didn’t exist yet until the flash was created. So I switch things up and applied css to the paragraph tag instead of the div:

<div id="notice">                       
 <% if flash[:notice] -%>
  <p><%= flash[:notice] %></p>
 <% end -%>
</div>

Now for the fun part… err umm not so fun error handling. You’ll notice that the if @team.save has an else like usual. So we can do format.js like above. First if there were errors I would shake the entire paragraph tag that contains the label, input and button. This is some more scriptaculous goodness and really tells the user there’s something wrong. Next because we are only working with one input we can replace the html inside the label with @team.error.full_messages and add a class name so we can turn it red so they know there’s an error on that field.

That’s it!! Pretty simple stuff. Also if you have something more complex with multiple input and fields we can handle the errors a bit differently. First you can put an empty div on your page somewhere:

<div id="ajax_form_errors"></div>

Then in the else statement just add this into the format.js block:

page.replace_html :ajax_games_form_errors, :partial => "partials/assets/errors"

Then the errors.html.erb partial:

<div id="errorExplanation" class="errorExplanation">
 <h2><%= @game.errors.count %> errors prohibited this game from being saved</h2>
 <p>There were problems with the following fields:</p>
 <ul>
  <% @game.errors.each_full do |msg| -%>
   <li><%= msg %></li>
  <% end -%>
 </ul>
</div>

What were doing here is basically just the same thing ActiveRecord::Errors does with it default setup for error handling. Looping over the errors and printing them out in a list item.

That’s it that’s all. Lemme know if you have any problems and I’ll try and help you out the best I can.

Leave a Comment
post icon

Safari renders blank page with Ruby on Rails 2.3 >

If you have upgraded your Rails to version 2.3 you might notice Safari renders a blank page when you access your localhost to view your app. Apparently it’s because the newer versions of Rails don’t work well with older versions of Mongrel. The fix is simple:

sudo gem update mongrel
Leave a Comment
post icon

Advanced Rails Recipes – Keeping Forms Dry and Flexible – Plugin

I’ve updated the previous patch of ElevatedFormBuilder to a Ruby on Rails plugin. You can now install it as a plugin from my github:

script/plugin install git://github.com/darrenterhune/elevated_form_builder.git

If anyone has any problems just add comments below.

Formtastic is far superior than this plugin so you should check that out instead.

Leave a Comment
post icon

Advanced Rails Recipes – Keeping Forms Dry and Flexible Patch

Update: This patch can now be installed as a rails plugin from my github.

I recently committed a patch for the “Keeping Forms Dry and Flexible” recipe found in Advanced Rails Recipes Book. The original recipe was written by Mike Mangino of Elevated Rails. The first time I used the recipe found in the book, I was pretty impressed… almost. Being a usability and accessibility freak that I am I saw that if you passed in the custom :label option (This is to print a custom label instead of the default table column name, which would be in this case… “Title”):

<%= f.text_field :title, :label => "custom label here" %>

This would print:

<label for="controller_title">Custom label here</label><input id="controller_title" type="text" value="some value here" size="30" name="controller[title]" label="custom label here"/>

Wha? There’s a label param in the input element? That’s not allowed!.  So I went off to Mike’s website and contacted him asking him if he had any updates to this recipe. He gladly created a new repository on github for me to pull from. I grabbed his new version of the error_handling_form_builder. Wow it’s different! Wow it’s got 2 form builders! One that lets you use templates like in the book and a more customizable one, that just uses content_tag methods to build a form. Both are pretty sweet and both use the same helper method. However when I tested, it still printed the label in the input. So I did a patch and Mike did a patch and now we have a dry, flexible, accessible, usable and badass form builder with 2 options for building forms! Or of course from Mike’s github.

Leave a Comment
post icon

RubyProf error “can’t convert Fixnum into String”

I recently maxxxxed out my memory limit on my regular dreamhost account at work causing 500 errors all over the place. This is now forcing me to start learning how to cache, and trace my apps for memory and performance. I also switched to PS with 300mb burstable to around 700mb. That should help out for now. Anyway, back to finding out which requests are drinking redbull… I installed the ruby-prof gem to find out. I ran a request with the param key added to the end of the url and wham! Errors? WTF? I copied the code right out of “Advanced Rails Recipes” correctly, and checked it 10 times? So what’s the error? “can’t convert Fixnum into String”? Well it seems that the printer class is trying to convert a number to a string, which just won’t happen. It was pretty obvious what was happening:

response.body << printer.print("", 0)

Right there! It’s trying to append the request body to the printer class with a integer passed as a hash. I haven’t looked at the ruby-prof code but the class doesn’t like that. So I just put quotes around it.

response.body << printer.print("", '0')

Then it worked out fine! Hope that helps someone out cause I spent about 2 hours searching for the problem.

Leave a Comment