views:

31

answers:

1

I'm having trouble figuring out how best to model my data. I have the following two models in my Rails application:

class Foo < ActiveRecord::Base
  belongs_to :active_bar, :class_name => 'Bar'
  accepts_nested_attributes_for :active_bar

  before_create do |f|
    f.active_bar.foo = f

    # Causes stack overflow!
    f.active_bar.save!
  end
end

class Bar < ActiveRecord::Base
  belongs_to :foo
end

test 'create with nested attributes' do
  f = Foo.create!(:name => 'foo-name', :active_bar_attributes => {:name => 'bar-name'})
  assert_equal 'foo-name', f.name
  assert_equal 'bar-name', f.active_bar.name
  assert_equal f, f.active_bar.foo

  f_id = f.to_param

  retrieved_f = Foo.find_by_id!(f_id)
  assert_equal retrieved_f, retrieved_f.active_bar.foo
end

What you probably think is strange is the reflexive belongs_to relationship I'm attempting to model. My plan is that, eventually, Foo will have many instances of Bar while one instance will be considered "active". Thus I'm using active_bar to refer to this active instance. The problem with this code is that I need to set the foo property in Bar back to the parent Foo instance and I can't figure out the best place to do it (the save! call in before_create ends up being recursive and overflowing the stack) or even if this is the cleanest way to model this type of relationship.

Essentially I'm attempting to model a user (equivalent to Foo) who has multiple e-mail addresses (equivalent to Bar) with one of the e-mail addresses marked as the user's primary address.

Any advice?

+1  A: 

I'm just going to respond in terms of User and EmailAddress if that's okay with you ;)

In your User model should really be has_many :email_addresses, has_one :active_email, :class_name => 'EmailAddress' and, as you correctly identified, accepts_nested_attributes_for :email_addresses

The EmailAddress model should then, of course, have belongs_to :User.

Aside from these, I think you are over-thinking things. In the form to create a user, then, allow them to enter as many email addresses as they want and either have them put their "active" email first, or have some sort of toggle to denote which email address is their primary address.

Edit: As far as the before_create statement, I think it only needs to be a simple validation that a primary email address has been given/marked (if it is necessary that they specify an email address in the first place).

If this doesn't fulfull what functionality you need, please comment. I'll try and help more.

davidcelis
Thanks for the tips! When I get a chance I'll try it out.-Richard
Richard Cook