2012-10-26 4 views
5

Je suis novice dans le domaine du rubis et des rails et je souhaite suivre au mieux les normes et les conventions afin de ne pas prendre de mauvaises habitudes. J'ai deux modèles: cours et emplacement. Un cours appartient à un emplacement, car un cours ne peut avoir qu'un seul emplacement. Un emplacement a beaucoup de cours, car un emplacement peut être partagé par plus d'un cours.Je n'arrive pas à comprendre comment les modèles et les associations sont sauvegardés dans les rails

Lors de la création d'un cours, il se peut qu'il existe déjà un emplacement identifié par son ID. Ou l'emplacement n'existe peut-être pas encore, auquel cas un nouvel enregistrement d'emplacement doit être créé. Mon contrôleur de cours a l'action de création suivante.

def create 
    @course = Course.new(params[:course]) 

    if params[:course][:location][:id].blank? 
    @course.location = Location.create(params[:course][:location]) 
    else 
    @course.location = Location.find_by_id(params[:course][:location][:id]) 
    end 

    @course.save 

    respond_with @course 
end 

Notez qu'il s'agit d'une API REST qui répond uniquement avec JSON. Le javascript qui rend les messages de demande un tableau JSON dans le même format qui serait renvoyé par une requête GET

{ 
    "course": 
    { 
    "title":"US History", 
    "credits":"3", 
    "max_students":"100", 
    "location": 
    { 
     "id":"", 
     "building":"Freedom Hall", 
     "room":"301" 
    } 
    } 
} 

or 

{ 
    "course": 
    { 
    "title":"US History", 
    "credits":"3", 
    "max_students":"100", 
    "location": 
    { 
     "id":"12", # this is the only difference 
     "building":"Freedom Hall", 
     "room":"301" 
    } 
    } 
} 
  1. Par rapport à tous les exemples que je l'ai lu, ce code ne semble pas si élégant . Y a-t-il une meilleure façon de le prendre en compte?
  2. Si Location.create déclenche une exception, @ course.save sera-t-il toujours appelé? Dois-je utiliser Location.create !?
  3. De même, les erreurs de validation se retrouveront-elles dans @ course.errors même si les erreurs se trouvaient sur le modèle Location? Ai-je besoin de sauver de l'exception pour que je puisse retourner les erreurs au client?

Merci beaucoup pour toute l'aide!

Répondre

2

Vous pouvez nettoyer ça à l'aide find_or_initialize_by_id. Cela devrait fonctionner:

def create 
    @course = Course.new(params[:course]) 
    @course.location = Location.find_or_initialize_by_id(params[:course][:location][:id], 
                 params[:course][:location]) 
    @course.save 
    respond_with @course 
end 

En ce qui concerne votre deuxième question, dans votre code que vous avez @course.save ne sera pas appelée si Location.create (ou Location.find) soulève une exception (parce qu'ils se produiraient en premier). Cependant, la façon dont je l'ai codé ci-dessus, l'exception se produirait au même point dans le code, quand save est appelée, à quel point l'association est également enregistrée.

+0

Merci! Je me penchais vers quelque chose comme ça mais j'avais froid aux pieds. Et vous avez confirmé mes soupçons sur le traitement des exceptions - je ne savais pas s'il se passait quelque chose en coulisse qui pourrait affecter mes attentes. Est-ce que cela nécessite d'ajouter 'accepts_nested_attributes_for: location' à mon modèle de cours? – glevine

+0

De rien. Non AFAIK vous ne devriez pas avoir à ajouter 'accept_nested_attributes_for: location' pour ce faire puisque vous définissez explicitement les attributs sur l'emplacement. Bien que, si vous aviez des attributs imbriqués, je crois que vous seriez capable de tout initialiser avec '@course = Course.new (params [: course])', et les attributs 'location' seraient automatiquement définis. Je n'ai pas testé cela mais je ne sais pas si cela fonctionnerait quand l'emplacement 'id' est défini. –

+0

Je vais devoir écrire quelques tests, mais une fois que je le ferai, j'ajouterai un commentaire avec mes résultats.Ma crainte est que si 'id' est défini sur l'emplacement imbriqué, mais que tous les autres champs sont vides, alors les rails mettraient à jour les attributs sur l'emplacement correspondant, en les plaçant vides (en supposant que les champs vides sont valides) record. Cela entraînerait l'effacement des données dans l'enregistrement de localisation. Mais je ne peux m'empêcher de penser que les rails sont assez intelligents pour savoir quoi faire. Comme je l'ai dit, je vais répondre à nouveau une fois que je sais comment cela fonctionne réellement. – glevine

1

Essayez cela, dans votre contrôleur

def new 
    @course = Course.new 
    @location = @course.location.build # if one..many relationship 
    @location = @course.build_location # if one..one relationship 
end 

def create 
@course = Course.new(params[:course]) 
if @course.save 
    respond_with @course 
else 
    render :action => "new" 
end 
end 

plus sur nested_attributes

+0

Merci pour la réponse! Quel est l'avantage de faire cela, par opposition à l'utilisation de find_or_initialize_by_id? J'ai besoin d'en savoir plus sur les modèles imbriqués. Je suppose que je n'avais pas connecté les points avec ceci étant lié à l'imbrication. – glevine

Questions connexes