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.