01 Nov, 2007

Published at 07:51PM

Tagged with forms, programming, rails, and tips

This post has 5 comments

Handling multi-model forms in Rails

Sometimes (a lot of times, actually) I need to post a form that deals with several different models. For instance, in Golf Trac, fields_for "course[course_holes][]" passes an array of hole attributes that relate back to a course, where a course has_many holes. A course also has_many tees, so there’s a fields_for "course[course_tees][]", as well. This post isn’t about how to setup the forms, but more of what to do in the model.

Of course, I’m sure there are a lot of different ways to do this, but here’s my approach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Course < ActiveRecord::Base

  has_many :holes, :dependent => :destroy
  has_many :tees,  :dependent => :destroy

  def course_holes=(course_holes)
    set_model_attributes(:holes, course_holes)     
  end

  def course_tees=(course_tees)
    set_model_attributes(:tees, course_tees)
  end

  private

  def set_model_attributes(model, model_attributes)
    model_attributes.each_with_index do |attributes, index|
      if attributes[:id].blank?
        send(model).build(attributes)
      else
        _model = send(model).detect {|m| m.id == attributes[:id].to_i}
        _model.attributes = attributes
      end
    end
  end

end

I’m going to need the set_model_attributes method in a few other places, so it’ll eventually end up in a module.

Comments

Chris Friday, 02 Nov, 2007 Posted at 06:05AM

I haven’t messed with it yet, but check out conductors. It might be just what you are looking for.

Ryan Sunday, 04 Nov, 2007 Posted at 02:14PM

It looks pretty cool. But the way I have things set up now, my controllers look exactly the same as they would if they were setup for only one model. I wrote a module with a few generic model helpers that assist with multiple associations, so I don’t know if I need something quite like a conductor (yet, anyway).

Plus, part of me thinks adding more layers to MVC kind of makes things unnecessarily complex. Of course, the presenter/conductor idea is probably for situations where it would be even more complex to not use.

Do you plan on using it?

Chris Sunday, 04 Nov, 2007 Posted at 03:13PM

I try to avoid forms that manipulate multiple models ;-p

I agree that an extra layer of abstraction can make it a bit more complex. However, I also would say that coupling the models too tightly can make them muddy and somewhat confusing. The benefit of a separate layer is that you keep model x from being responsible for setting up model y on a form submission.

If you think of a conductor as an abstract “super” model, then in makes sense in some ways. Then, you would simply create a controller that handles the new model.

In the end, I’m just a fence-rider, simply because I haven’t needed to deal with this situation. When/if I do, I’ll pick a side :-)

Ryan Sunday, 04 Nov, 2007 Posted at 06:18PM

I don’t think I’ve ever gotten into this multi-model form business before, but I’ve learned that it becomes a pain quick. I tried to come up with ways to avoid it, but there really isn’t one that I can see.

A golf scorecard has different tees, yardages, handicaps, pars, slope/rating, mens/ladies, general course info, and so on. I thought about going one step at a time, using Ajax to replace the current form when completed, but then editing becomes a pain. I think it would have been far too much Ajax, anyway. And going page-to-page to build the scorecard felt like a 1995 thing to do.

I suppose it’s just the nature of the beast.

It took me a while to see the value in the “presenter pattern” or whatever, and since this is the first I’ve heard of a conductor, maybe I just need a little more time for the idea to settle. I’m definitely open to other options, though.

Thomas Lee Tuesday, 11 Nov, 2008 Posted at 08:29AM

Hi,

I thought multi-model forms in Rails sucked too, so I wrote a plugin that changes the way the parameter parser works:

http://www.deskchecked.com/2008/07/20/taking-the-pain-out-of-complex-forms-in-rails/

It’s better suited to complex forms IMO, but still needs some development work.

Also get vocal on this patch if you’d like to see it in a future version of Rails:

http://rails.lighthouseapp.com/projects/8994/tickets/1142-simplified-parameter-parsing-code

Cheers, T

Do you have something to say about this post?
Retype the image to the right Spam Hint: Are You Human? Textile Formatting Tips

or

Ryan Heath | Site Management A Ruby on Rails production.

This site is a Formed Function. Formed Function LLC | @formedfunction | Get in Touch