2010-07-16 78 views
0

我很难搞清楚如何最好地建模我的数据。我有以下两种模式在我的Rails应用程序:Rails/ActiveRecord:has_one,belongs_to和before_create

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 

什么你可能觉得很奇怪是自反belongs_to关系,我试图建模。我的计划是,最终,Foo将有许多Bar的实例,而一个实例将被视为“活动”。因此,我使用active_bar来引用此活动实例。此代码的问题是,我需要将Bar中的foo属性设置回父代Foo实例,我无法弄清楚最好的做法(save!调用before_create最终会递归并溢出堆栈)或者即使这是对这种类型的关系建模的最干净的方式。

本质上我试图模拟一个用户(相当于Foo)谁拥有多个电子邮件地址(相当于Bar)与其中一个电子邮件地址标记为用户的主要地址。

有什么建议吗?

+0

我想我会将'before_create'中的代码移动到'after_create'中代替。这似乎工作。然而,我仍然不完全满意于模拟的关系。 – 2010-07-16 18:10:51

回答

2

我只是在用户和EmailAddress的方面回应,如果这与你没关系;)

在用户模式确实应该has_many :email_addresseshas_one :active_email, :class_name => 'EmailAddress',正如你正确识别,accepts_nested_attributes_for :email_addresses

那么EmailAddress模型当然应该有belongs_to :User

除了这些,我认为你是过度思考的东西。然后,在创建用户的表单中,允许他们输入任意数量的电子邮件地址,并让他们首先放入“活动”电子邮件,或者进行某种切换以表示哪个电子邮件地址是其主要地址。

编辑:至于before_create语句,我认为它只需要一个简单的验证,主要电子邮件地址已被给予/标记(如果它是必要的,他们首先指定一个电子邮件地址)。

如果这不能满足您需要的功能,请发表评论。我会尽力帮助更多。

+0

感谢您的提示!当我有机会时,我会尝试一下。 - 理查德 – 2010-07-21 01:42:14

+0

我有同样的问题。 “active_email_id”的实际值存储在哪里?不应该把'has_one'当成rail_ terms来使用 - 虽然英文看起来很糟糕。 – KDM 2014-10-08 09:23:02