Topic: Extracting service from a form with nested forms

Hi,

Lately I'm facing some issue with extracting some form models[1] from AR::Base, based on point 3 of CodeClimate - 7 ways to decompose fat AR models . I'm already applying it in some parts for simpler stuff, because it's fairly easy to do with simple objects, or even when having 1-1 connections within the form. But it's starting to be overwhelming when complex logic, and multiple subforms kicks in.

Lets take an example, like:

class Account
  has_one :gallery
end

class Gallery
  has_many :images
  belongs_to :account
end

class Image
  belongs_to :gallery
end

# then in the form
<%= form_for account do |af| %>
   ..
   <%= fields_for :gallery do |gf| %>
    ..
    <%= fields_for :images do |imgf| %>
       ..
    <% end %>
  <% end %>
<% end %>

And lets also say that we have at least two places were we use it, so views and model validations are cluttered with if-else dependent behavior - because of differences, like additional field or different validations depending on some state, etc.

The question is, how would you refactor it, without using nested_attributes_for within AR models, with (if possible) having a possibility to use the fields_for form helper?

Currently I would try to make some kind of base form models, for each of the model, ie AccountForm::Base, GalleryForm::Base, etc. with some shared behaviors like validations or attributes. Then for each of the use case, creating maybe something like AccountForm::Wizard, which would inherit from base, and add additional logic for saving etc. But I'm not quite sure if it's a good way to go, is it? Also when having even more nested forms doesn't it seems like a bit of overkill? Maybe just inherit from AR and have some more goodies?

PS. I searched web a lot last days, in search of a proper and a clean way to do it, but I haven't found any good solutions, with `real life examples` and `facts`. If I missed something that covers the topic then please share a link.

EDIT 1:
Please also consider testing solutions of such thing, with my solution I would need to load at least active_model or stub it like Avdi Grimm does it within Objects on rails. At least it won't touch the database.

[1] when I say Form Models, I mean models that quack like ActiveModel

Last edited by zalesz (2013-03-19 09:08:03)