Archive for the ‘Rails’ Category

The (Rails) times they are a-changin’?

April 26, 2012

I always knew we wouldn't last forever.

I just attended my first RailsConf, and I feel a little sad.

Oh, the irony. I attend my first conference devoted to the development tool I’ve been devoted to for the last six years, and my overwhelming feeling is that it’s time to move on…to a new development paradigm and a new toolset.

What I heard from DHH, Aaron Patterson, and Yehuda Katz in their conference addresses was this:

“The web dev paradigm is shifting under our feet. All the fun is moving to the browser, which means to Javascript. Weren’t we prescient to embrace REST years ago so that we can now become a great web service platform, dishing out JSON from a thousand endpoints of API light as a sort of workhorse for the sexy stuff the JS guys and gals are doing. (If we hadn’t done that, we might already be a dinosaur.)

“Oh, and be prepared, because we may do something crazy. Like coming up with some sort of browser/Javascript framework for Rails, because we want to do the sexy stuff too.”

Oh, Rails. The writing is already on the wall, I’m afraid. The future web dev paradigm is already being speedily developed. (If I had to pick its embodiment right now, I’d lay my money on Meteor.)

Ruby is a fantastic language. I am not even a 7 with Javascript. But my new projects, at least the side ones, are going to be in Meteor.

Jack Welch said, “Change before you have to.” Don’t wait too long.

Why is my select value not selected?

November 19, 2010

Hours battling this one. Symptom: select tag in a form was not displaying the value of the attribute from the database, although one could select a new value and have it saved as expected.

Had a simple (!) select tag, looked something like this:

  <%= :state, options_for_us_state %>

No matter what manner of manipulation I did, including explicitly setting :selected =>, would cause the value of the state attribute from the ActiveRecord object to be selected upon page presentation.

After digging through the Rails code, I noticed that the select form helper was calling options_for_select. Looking at that code, I noticed that if the container of options that is passed in is a String, no :selected or :disabled processing is done.

But I’m not passing in a string, I’m…oops, my options_for_us_state helper was already calling options_for_select, thus giving me a string, thus bypassing the :selected and :disabled processing.

Interestingly, it created the select tag just fine, which is what did me in for so long.

Seems like possibly a Rails oversight. The doc for options_for_select doesn’t say that you can pass in a String. Nor does it say that you can’t, and Strings do respond to the each method.

But still, it’s odd behavior, no?

Rails nested forms with AJAX add and remove

June 24, 2010

If you’ve found this, no doubt you’ve discovered that there are many solutions to the issue of nested forms in Rails. This is one of those many solutions. The highlights include:

  • supports unlimited nesting levels
  • uses (and requires) accepts_nested_attributes_for; no special model code required
  • new nested objects are instantiated and saved to the database before being exposed in the view
  • adding and removing nested forms happens dynamically in the user interface
  • jQuery UI is used for the JavaScript stuff (though it could be easily re-written to use raw Javascript or another library)

One level of nesting

Let’s start by getting one level of nesting working. I’ll refer to the “parent” model (the one that has_many somethings) and the “child” model (the one that belongs_to the parent). If I use the term “parents” or “children,” I will sometimes want you to specify the plural. This should be obvious by the context.

Set up the model

Give the Parent the usual has_many declaration and the accepts_nested_attributes_for declaration. The latter allows us to add, edit, and delete children “inside” a parent update. (See the API doc.)

  has_many :children
  accepts_nested_attributes_for :children

It’s worth noting that we do not need the :allow_destroy option set on accepts_nested_attributes_for. This is because we will do our own destroys dynamically, and don’t need the method provided by ANAF.

Give the Child model the usual belongs_to declaration, and that’s it for the model.

Give your routes a REST

Be sure you have a route something like the following in routes.rb. The important thing is that you have a route with the parent at the root, having many children.

map.resources :parents, :has_many => :children

Step 2 – controllers

The Parent controller needs no changes at all. It simply needs to do the usual actions to retrieve a Parent object for rendering.

A little AJAX in the Children controller

We need to have our Children controller respond to AJAX requests to add and remove children from the database. I’ll start by showing the code:

# GET /parents/1/children/new (AJAX)
def new
  parent = Parent.find(params[:parent_id])
  @child = parent.children.create
  new_child_form = render_to_string :layout => false
  new_child_form.gsub!("[#{}]", "[#{}]")
  render :text => new_child_form, :layout => false

# DELETE /parents/1/children/1 (AJAX)
def destroy
  parent = Parent.find(params[:parent_id])
  unless parent.children.exists?(params[:id])
    render :text => { :success => false, :msg => 'the child was not found.' }.to_json and return
  if parent.children.destroy(params[:id]) // Rails < 2.3.5, if parent.children.destroy(Child.find(params[:id]))
render :text => { :success => true }.to_json
    render :text => { :success => false, :msg => 'something unexpected happened.' }.to_json
  • note that this is an AJAX-only controller; I assume that I will always create and delete children via AJAX (and edit them via nested edits from their parent)
  • the new action does two main things: 1) creates a new child object (saving it to the database) and 2) creates a chunk of HTML to send back to the browser to render the nested form for the new child
  • render_to_string renders new.html.erb (see below) to a string so that we can manipulate it in the next statement
  • when Rails renders new.html.erb, it inserts as the index of children_attributes; not sure why, but I guess since the view is not being rendered in the context of a FormBuilder, it decides that’s the best thing to use as the index; but…
  • …we need a real index, and it needs to be a number greater than a) the indices that Rails has created for children already in the database, and b) any indices that we’ve generate previously on this form
  • so we use, which will always be a very big number and, since time waits for no one, will always be larger than the last time we used it
  • the delete action is simpler, and returns a JSON-formatted response to the caller

For your viewing pleasure

Since we just talked about rendering the HTML fragment for the new child record we created, let’s have a look at the view that is rendered (new.html.erb):

<% fields_for 'parent[children_attributes][]', @child do |child_form| %>
 <%= render :partial => '/children/form', :locals => { :f => child_form, :child => @child } %>
<% end %>

Must you render a partial in this view? No, but since you want a newly added child form to look just like one that was rendered the old-fashioned way in the first place, using a partial will keep your views DRY.

What does the partial look like? Like any old partial, with a few mandatory elements to enable our AJAX methods:

  f - form context
  child - Child to be displayed

<div class='child' id='<%= %>'>
  <%= f.hidden_field :id %>
  <p><a href='#' class='child-remove'>Remove the child above</a></p>

The important thing here are the classes and ids. They are mandatory, and must be specified exactly as shown here.

Careful readers have noted that we’ve set ourselves up here to delete any child, but what about adding children? Well, that is done in the parent view, right? Because while we need a delete on every child record, we only need a single add link. Here’s the relevant chunk of the parent view:

<div class='children' id='parent-<%= %>'>
  <% parent_form.fields_for :children do |child_form| %>
    <%= render :partial => '/children/form', :locals => { :f => child_form, :child => child_form.object } %>
  <% end %>
  <div id='new-children'>
  <p><a href='#' class='child-add'>add a child</a></p>

Pretty straightforward. Again, the important thing here are the classes and ids. Also, note the “new-children” div: it too is required.

Tying it all together

So what ties all this together? A bit of JavaScript, of course. In your parent form, add this at the bottom:

$(document).ready(function() {
 dynamicAddRemove('parent', 'parents', 'child', 'children');

This sets up the appropriate handlers, calling dynamicAddRemove and telling it that “parent” is the parent object and “child” the child object. (Since JavaScript doesn’t have (direct) access to Rails’ inflectors, I specify both the singular and plural forms as arguments to dynamicAddRemove. There are several possible solutions to this admittedly ugly construct, which are left as exercises for the reader.)

Which brings us to the final piece of this solution: the JavaScript that actually performs the adds and removes. Stick this in your public/javascripts/application.js file:

function dynamicAddRemove(parent, parents, child, children) {
  $('a.' + child + '-add').live('click', function() {
    var parentId = $(this).closest('.' + children).attr('id').replace(parent + '-', '');
    indexData = ''
    // check to see if there is a parent div; this will be the case if we're doing a
    // grandchild (or deeper) insert
    if ($(this).closest('div.' + parent).size() > 0) {
      var matcher = new RegExp (parents + '_attributes\\]\\[(\\d*)\\]');
      var parentIndex = $(this).closest('div.' + parent).find(':input').attr('name').match(matcher)[1];
      indexData = 'index=' + parentIndex;
    $.get('/' + parents + '/' + parentId + '/' + children + '/new', indexData, function(data) {
      $(data).hide().appendTo($('div.' + children + '#' + parent + '-' + parentId + ' div#new-' + children)).fadeIn('slow');
    return false;

  $('a.' + child + '-remove').live('click', function() {
    var childId = $(this).closest('.' + child).attr('id');
    var parentId = $(this).closest('.' + children).attr('id').replace(parent + '-', '');
    $.post('/' + parents + '/' + parentId + '/' + children + '/' + childId, { _method: 'delete' }, function(data, textStatus) {
      var response = JSON.parse(data);
      if (response.success) {
        $('div.' + child + '#' + childId).fadeOut('slow', function() {
      } else {
        alert('The ' + child + ' could not be removed because ' + response.msg);
    return false;

That’s all there is to it.

Cheat sheet

Here’s a cheat sheet to help you get all the divs, classes, and ids set up correctly.

(in the parent edit view)

<div class='children' id='parent-nnn'>
<div id='new-children'>
  <p><a href='#' class='child-add'>add a child</a></p>

(in the child partial)

<div class='child' id='nnn'>
  <a href='#' class='child-remove' />

Of course, the “nnn”s are replace by the id of the appropriate record, as in and

More layers of nesting

And what about another layer of nesting, as promised?

It’s rather simple, really. Just repeat the above instructions, changing “parent” and “child” appropriately. IOW, if you’re adding a “lower” level, your parent will now be the child from the level above.

When you add the call to dynamicAddRemove, put that bit of code in the original parent view. IOW, all of the calls to dynamicAddRemove will wind up in one place: the highest level view in your hierarchy.

There are two critical differences, one in the child new.html.erb view and one in the child controller.

We need to specify the appropriately nested “path” to the child record we’re maintaining. So, for the next level down, our “grandchild” new.html.erb would look like this:

<% fields_for "grandparent[parent_attributes][#{@parent_index}][child_attributes][]", @child do |child_form| %>

And where does @parent_index come from? Well, we need one more line added to the child controller:

@parent_index = params[:index]

Insert it right before the render_to_string.

You can no doubt see how to extend this to greater levels of nesting. Note that if you add a level, you’ll have to edit the JavaScript in application.js and find the “grandparent index” and pass it along to the controller in the add portion of the script.

Credit where credit can be remembered

In arriving at this solution, I looked at many, many solutions; many of which I can no longer find or remember. Certainly a shout out to Ryan Bates for this and this. And thanks to Geof Dagley for guidance.

If I should credit you too, let me know.


Enjoy, and let me know if this works for you. Have a better way?…let me know.