public
Description: Conductor is a Rails plugin which helps you manage creating and updating a record and its associations via a single form submission
Homepage:
Clone URL: git://github.com/jonleighton/conductor.git
jonleighton (author)
Sun Jan 25 16:35:54 -0800 2009
commit  ba3c44c19c61ee4610f97637c606ec6b6f04ca7e
tree    6656fd81c01f461840af90d56c7f6aa44659dc70
parent  102e83d999e88f2c68239a8b280b520fe4dec569
name age message
file .gitignore Sun Jan 25 16:05:34 -0800 2009 Some rdoc commentifying [jonleighton]
file MIT-LICENSE Tue Sep 02 02:25:31 -0700 2008 Import some README text [jonleighton]
file README.textile Sun Jan 25 16:35:54 -0800 2009 Updating readme [jonleighton]
file Rakefile Sun Jan 25 16:05:34 -0800 2009 Some rdoc commentifying [jonleighton]
file TODO Sun Jan 25 16:25:00 -0800 2009 Updating readme [jonleighton]
directory example/ Sun Jan 25 14:53:02 -0800 2009 Comments for the example app [jonleighton]
file init.rb Wed Jan 21 07:40:46 -0800 2009 Get rid of the vendored version of ActiveSuppor... [jonleighton]
file install.rb Tue Sep 02 02:05:18 -0700 2008 Initial import [jonleighton]
directory lib/ Sun Jan 25 16:05:34 -0800 2009 Some rdoc commentifying [jonleighton]
directory spec/ Sun Jan 25 13:10:50 -0800 2009 Add an error_messages_for_conductor method and ... [jonleighton]
directory tasks/ Tue Sep 02 02:05:18 -0700 2008 Initial import [jonleighton]
file uninstall.rb Tue Sep 02 02:05:18 -0700 2008 Initial import [jonleighton]
README.textile

Conductor Plugin

Conductor is a Rails plugin which helps you manage creating and updating a record and its associations via a single form submission. More generally, it is an implementation of the Unit of Work design pattern.

What it does:

  • Allows complex nested parameters to represent associations
  • Creates, finds or deletes the associated objects as necessary
  • Performs database changes only when told to and within a transaction
  • Aggregates error messages occurring on the objects it manages

This plugin is written by Jon Leighton. You can contact me at j at jonathanleighton dot com.

Overview

Please see the example app for a fully working version of the code below.

Manually parsing form data

Conductor can be used as an object-oriented way to parse form data – it gives a place to put code which doesn’t really belong in either the controller or the model.

class BookConductor < Conductor::Base
  def publisher=(publisher_name)
    record.publisher = Publisher.find_by_name(publisher_name)
  end
end

Automatically managing associations

In its simplest form, we can do the following:

class Book < ActiveRecord::Base
  has_many :tags
end

class BookConductor < Conductor::Base
  has_many :tags
end

@book = Book.find(4)
@book.tag_ids # => [4, 6, 3]

@book_conductor = BookConductor.new(@book)
@book_conductor.tag_ids = [5, 2, 6]

# Neither the database nor the @book object have changed because we haven't saved the conductor:
@book.tag_ids # => [4, 6, 3]

@book_conductor.save # => false - the @book still hasn't changed because something failed, so all changes were rolled back

# ... fix the problem ...

@book_conductor.save # => true
@book.tag_ids # => [5, 2, 6]

We can do more complex things as well, including creating/updating join records on the fly:

class Book < ActiveRecord::Base
  has_many :authorships
  has_many :authors, :through => :authorships
end

class BookConductor < Conductor::Base
  has_many :authorships, :require => :author_id
end

@book_conductor.authorships = {
  # Record doesn't exist (no id field) and won't be created (no author_id field)
  0 => { :role => "" },
  
  # Record is currently associated, but will be removed (no author_id field)
  1 => { :id => 5, :role => "Lead Writer" },
  
  # Record doesn't exist (no id field), but will be created and associated with the book
  2 => { :author_id => 34, :role => "Editor" }
}

Known Problems

Patches welcome!

  • Currently only works with PostgreSQL
  • The documentation sucks. I am rubbish at writing documentation, so it would be really great if some people could write tutorials/blog posts/etc…

Relationship with the Presenter pattern

This started out as an implementation of a conductor as described by New Bamboo in their blog post “Presenters and Conductors on Rails”.

A conductor initially seems similar to a presenter, particularly as the example Jay Fields gives manages multiple objects in order to keep the controller concise. However, the distinction in my mind is this:

  • A presenter handles view-related state and behaviour in a cleaner and more object-oriented way than helpers
  • A conductor assists the controller in parsing form parameters into one or more objects, and saving them