Monday, March 2, 2009
I cringe a little bit when I see a controller like this:
class Admin::Subscribers::InvitationsController < Admin::ApplicationController
before_filter :load_subscriber
before_filter :build_invitation, :only => [:new, :create]
def build_invitation
@invitation = @subscriber.invitations.build(params[:invitation])
@invitation.email = @subscriber.email # *shudder*
end
end
While it’s almost okay, it irks me to have to explicitly set the Invitations’s email address in the controller12.
What I really want is to set the email address when I make an Invitation for a Subscriber. There should only be two ways to say that:
@subscriber.invitations.build
@subscriber.invitations.create
So, let’s place the responsibility for setting the Invitation’s email address directly inside the Subscriber’s has_many association:
class Subscriber < ActiveRecord::Base
has_many :invitations, :as => :source, :extend => DefaultAssociationAttributes do
def default_attributes
{ :email => proxy_owner.email }
end
end
end
module DefaultAssociationAttributes
def build_record(attrs, &block)
super(with_default_attributes(attrs), &block)
end
def create_record(attrs, &block)
super(with_default_attributes(attrs), &block)
end
def with_default_attributes(attrs)
default_attributes.merge((attrs || {}).symbolize_keys)
end
end
And then clean up our controller:
class Admin::Subscribers::InvitationsController < Admin::ApplicationController
before_filter :load_subscriber
before_filter :build_invitation, :only => [:new, :create]
def build_invitation
@invitation = @subscriber.invitations.build(params[:invitation])
end
end
I’m feeling pretty happy with this idea, so I’m thinking I’ll keep the code around and maybe throw a small gem up on GitHub.
UPDATE: The gem’s now in my GitHub account as default_association_attributes.
I may have missed another solution though, so I’d love to hear from you—how have you solved this problem? How have you felt about your solution?
Having Invitation hang onto its own email address allows it to be re-used in non-Subscriber contexts—like when a User wants to create an Invitation for a friend.
↩Somehow, using a custom method like Subscriber#build_invitation_with_email doesn’t feel much better—then I have to remember to use it instead of the default.