Rails/ActiveRecord: has_one, belongs_to and before_create
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 ne开发者_开发知识库ed 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?
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.
精彩评论