Rails after_initialize uniquement sur “new”

J’ai les 2 modèles suivants

class Sport  :productable accepts_nested_atsortingbutes_for :product, :allow_destroy => true end class Product  true end 

Un sport ne peut exister sans le produit, alors dans mon sports_controller.rb j’ai:

 def new @sport = Sport.new @sport.product = Product.new ... end 

J’ai essayé de déplacer la création du produit vers le modèle sportif en utilisant after_initialize :

 after_initialize :create_product def create_product self.product = Product.new end 

J’ai rapidement appris que after_initialize est appelé chaque fois qu’un modèle est instancié (c’est-à-dire à partir d’un appel à la find ). Donc ce n’était pas le comportement que je cherchais.

Comment dois-je modéliser l’exigence que tous les sport aient un product ?

Merci

Placer la logique dans le contrôleur pourrait être la meilleure solution, comme vous l’avez dit, mais vous pourriez faire en sorte que after_initialize fonctionne comme suit:

 after_initialize :add_product def add_product self.product ||= Product.new end 

De cette façon, il ne définit le produit que si aucun produit n’existe. Cela ne vaut peut-être pas la surcharge et / ou est moins clair que la logique du contrôleur.

Edit: Par la réponse de Ryan, sur le plan de la performance, les éléments suivants seraient probablement meilleurs:

 after_initialize :add_product def add_product self.product ||= Product.new if self.new_record? end 

Sûrement after_initialize :add_product, if: :new_record? est la voie la plus propre ici.

Gardez le conditionnel hors de la fonction add_product

Si vous faites self.product ||= Product.new il recherchera toujours un produit à chaque fois que vous ferez une find car il doit vérifier si elle est nulle ou non. Par conséquent, le chargement ne sera pas très rapide. Pour ce faire, uniquement lorsqu’un nouvel enregistrement est créé, vous pouvez simplement vérifier s’il s’agit d’un nouvel enregistrement avant de configurer le produit.

 after_initialize :add_product def add_product self.product ||= Product.new if self.new_record? end 

J’ai fait quelques if self.new_record? base et vérifié if self.new_record? ne semble pas affecter les performances de manière notable.

Au lieu d’utiliser after_initialize , que diriez-vous after_create ?

 after_create :create_product def create_product self.product = Product.new save end 

Est-ce que cela semble résoudre votre problème?

On dirait que vous êtes très proche. Vous devriez pouvoir complètement supprimer l’appel after_initialize, mais je pense que si votre modèle Sport a une relation “has_one” avec: product comme vous l’avez indiqué, alors votre modèle de produit devrait également “appartenir à” sport. Ajoutez ceci à votre modèle de produit

 belongs_to: :sport 

La prochaine étape, vous devriez maintenant être capable d’instancier un modèle Sport comme ça

 @sport = @product.sport.create( ... ) 

Ceci est basé sur les informations de base de l’ Association des guides Ruby on Rails, que vous pourriez avoir une lecture si je ne suis pas tout à fait exact

Vous devez simplement remplacer la méthode d’initialisation comme

 class Sport < ActiveRecord::Base # ... def initialize(attributes = {}) super self.build_product self.attributes = attributes end # ... end 

La méthode Initialize n'est jamais appelée lorsque l'enregistrement est chargé à partir de la firebase database. Notez que dans le code ci-dessus, les atsortingbuts sont atsortingbués après la création du produit. Dans un tel paramètre, l'atsortingbution des atsortingbuts peut affecter l'instance de produit créée.