Ruby on Rails. Comment utiliser la méthode Active Record .build dans une relation: appartient à?

128

Je n'ai trouvé aucune documentation sur la méthode .build dans Rails (j'utilise actuellement 2.0.2).

Grâce à l'expérimentation, il semble que vous puissiez utiliser la méthode de construction pour ajouter un enregistrement dans une has_manyrelation avant que l'un ou l'autre enregistrement n'ait été enregistré.

Par exemple:

class Dog < ActiveRecord::Base
  has_many :tags
  belongs_to :person
end

class Person < ActiveRecord::Base
  has_many :dogs
end

# rails c
d = Dog.new
d.tags.build(:number => "123456")
d.save # => true

Cela enregistrera correctement le chien et l'étiquette avec les clés étrangères. Cela ne semble pas fonctionner dans une belongs_torelation.

d = Dog.new
d.person.build # => nil object on nil.build

J'ai aussi essayé

d = Dog.new
d.person = Person.new
d.save # => true

La clé étrangère Dogn'est pas définie dans ce cas car au moment de son enregistrement, la nouvelle personne n'a pas d'identifiant car elle n'a pas encore été enregistrée.

Mes questions sont:

  1. Comment la compilation fonctionne-t-elle pour que Rails soit suffisamment intelligent pour savoir comment enregistrer les enregistrements dans le bon ordre?

  2. Comment puis-je faire la même chose dans une belongs_torelation?

  3. Où puis-je trouver de la documentation sur cette méthode?

Je vous remercie

stellard
la source
Concernant la documentation, voir les guides Rails «Méthodes ajoutées par belongs_to» et «Méthodes ajoutées par has_one» . Plus de documentation technique peut être trouvée dans la documentation de l'API: belongs_toet has_one.
Dennis

Réponses:

147

Où il est documenté:

Depuis la documentation de l'API sous l'association has_many dans " Module ActiveRecord :: Associations :: ClassMethods "

collection.build (attributes = {},…) Renvoie un ou plusieurs nouveaux objets du type collection qui ont été instanciés avec des attributs et liés à cet objet via une clé étrangère, mais qui n'ont pas encore été enregistrés. Remarque: cela ne fonctionne que si un objet associé existe déjà, pas s'il est nul!

La réponse à la construction dans la direction opposée est une syntaxe légèrement modifiée. Dans votre exemple avec les chiens,

Class Dog
   has_many :tags
   belongs_to :person
end

Class Person
  has_many :dogs
end

d = Dog.new
d.build_person(:attributes => "go", :here => "like normal")

ou même

t = Tag.new
t.build_dog(:name => "Rover", :breed => "Maltese")

Vous pouvez également utiliser create_dog pour le sauvegarder instantanément (un peu comme la méthode "create" correspondante que vous pouvez appeler sur la collection)

Comment les rails sont-ils suffisamment intelligents? C'est magique (ou plus exactement, je ne sais tout simplement pas, j'aimerais le découvrir!)

BushyMark
la source
4
@BushyMark: il utilise method_missing ou metaporgramming pour ajouter ces méthodes avec define_method.
Federico
@Federico où la méthode manquante est-elle définie?
réveil
1
@ alock27 Identique à la façon dont ActiveRecord utilise la méthode manquante pour vos méthodes find_by_emailet find_by_column_name. Il convertit la méthode que vous passez en chaîne, la dissèque et essaie de la faire correspondre avec les noms de colonne de votre table.
bigpotato
@edmund Merci pour votre commentaire. Pour être clair, je comprends comment fonctionne method_missing. J'essayais de localiser l'emplacement réel du fichier qui définit cette méthode particulière manquante.
réveil
@ alock27 si vous demandez parce que vous voulez voir comment il est défini, vous devriez consulter Metaprogramming Ruby. Mais si vous recherchez vraiment l'emplacement réel, vous pouvez probablement rechercher le code source sur Google.
MCB
48
@article = user.articles.build(:title => "MainTitle")
@article.save
nehpets
la source
>> d.tags.build (: number => "123456") >> d.save # => true Pas la même chose?
antiqe