2010-07-16 6 views
0

Je n'arrive pas à trouver la meilleure façon de modéliser mes données. Je les deux modèles suivants dans mon application Rails:Rails/ActiveRecord: has_one, belongs_to et 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 

Qu'est-ce que vous pensez probablement est étrange est la relation belongs_to réflexive je tente de modéliser. Mon plan est que, finalement, Foo aura de nombreuses instances de Bar tandis qu'une instance sera considérée comme "active". J'utilise donc active_bar pour faire référence à cette instance active. Le problème avec ce code est que j'ai besoin de définir la propriété foo dans Bar retour à l'instance parent Foo et je ne peux pas trouver le meilleur endroit pour le faire (l'appel save! dans before_create finit par être récursif et débordant la pile) ou même si c'est la façon la plus propre de modéliser ce type de relation. Essentiellement, je tente de modéliser un utilisateur (équivalent à Foo) qui a plusieurs adresses de messagerie (équivalent à Bar) avec l'une des adresses de messagerie marquée comme adresse principale de l'utilisateur.

Un conseil?

+0

Je pense que je vais déplacer le code dans 'before_create' dans' after_create' à la place. Cela semble fonctionner. Cependant, je ne suis toujours pas complètement satisfait des relations comme modélisées. –

Répondre

2

Je vais répondre en termes d'utilisateur et EmailAddress si c'est d'accord avec vous;)

Dans votre modèle utilisateur devrait vraiment être has_many :email_addresses, has_one :active_email, :class_name => 'EmailAddress' et, comme vous avez identifié correctement, accepts_nested_attributes_for :email_addresses

Le modèle EmailAddress devrait alors, bien sûr, avoir belongs_to :User. Mis à part cela, je pense que vous êtes trop penser à des choses. Dans le formulaire de création d'un utilisateur, autorisez-les à entrer autant d'adresses e-mail que vous le souhaitez et demandez-leur de mettre en premier leur adresse e-mail «active» ou de sélectionner l'adresse e-mail principale. Edit: En ce qui concerne l'instruction before_create, je pense qu'il suffit d'une validation simple qu'une adresse e-mail principale a été donnée/marquée (s'il est nécessaire qu'ils spécifient une adresse e-mail en premier lieu).

Si cela ne correspond pas à la fonctionnalité dont vous avez besoin, veuillez commenter. Je vais essayer d'aider plus.

+0

Merci pour les conseils! Quand j'ai l'occasion, je vais essayer. -Richard –

+0

J'ai le même problème. Où la valeur réelle de 'active_email_id' est-elle stockée? Should_one' ne devrait pas être 'belongs_to' en termes de rails - bien que cela soit mauvais en anglais. – KDM

Questions connexes