Juste brièvement, j'ai rencontré un problème redouté 2 (n) requêtes. Si n = le nombre de compétences dans la base de données, mon formulaire d'édition de caractères # prendra 2 (n) requêtes pour charger la page. Il va sélectionner une compétence PlayerSkill (la table de jointure) une fois par compétence, et il recherchera la compétence une fois par compétence.Possibilité de créer des associations de chargement avec nested_attributes?
Voici un code que je crois pertinent à la situation. En substance, les modèles, vues et contrôleurs impliqués dans ce processus, moins les validations du modèle et moins les actions qui ne me concernent pas.
Le contrôleur:
# GET /characters/1/edit
def edit
@character = Character.find(params[:id], :include => {:player_skills => :skill})
stub_player_skills
end
private
def stub_player_skills
@skills = Skill.find(:all)
@skills.each do |skill|
if (skill.player_skills.empty?)
ps = @character.player_skills.build(:skill_id => skill.id, :name => skill.name)
end
end
end
Le modèle (s):
class Character < ActiveRecord::Base
belongs_to :user
belongs_to :campaign
has_many :sheets, :dependent => :destroy
has_many :tokens, :dependent => :destroy
has_many :player_skills, :dependent => :destroy
has_many :skills, :through => :player_skills
accepts_nested_attributes_for :player_skills, :allow_destroy => true
end
La vue incriminée (HAML):
%h1
Editing Character
- form_for @character do |f|
= f.error_messages
%p
= f.label :name
%br
= f.text_field :name
%p
= f.label :race
%br
= f.text_field :race
%p
= f.label :char_class
%br
= f.text_field :char_class
%p
-f.fields_for :player_skills do |ps|
=ps.object.skill.name
=ps.text_field :level
=ps.hidden_field :skill_id
-unless ps.object.new_record?
=ps.check_box '_destroy'
=ps.label '_destroy', 'Remove'
%br
%p
= f.submit
Ma compréhension de la situation est que le chargement désireux existe pour saisir l'association dans (grossièrement) une seule requête supplémentaire.
J'ai besoin d'appliquer correctement le chargement dans deux domaines, et je suis juste à une perte quant à la façon de le faire.
Dans la méthode stub_player_skills, il doit créer un objet PlayerSkill en supposant que le caractère n'en possède pas déjà un. Il pourrait bénéficier d'un chargement passionné ici, car il boucle à travers chaque compétence dans la base de données. C'est de là que viennent les premières "n-requêtes". Ensuite, dans la vue, fields_for parcourt toutes les PlayerSkills que nous avons accumulées, car il n'y a aucun moyen de charger avec impatience ici, quand j'appelle = ps.object.skill.name pour imprimer le nom de la compétence. fait une recherche de compétence, qui apporte le deuxième ensemble de "n-requêtes". Ma principale préoccupation réside dans la couche de vue, je ne trouve aucune documentation (Rails API ou autre) qui indique comment vous pouvez charger les associations avec impatience si vous utilisez fields_for pour générer un formulaire imbriqué.
Merci pour tout et toutes les réponses :) ~ Robbie
Cela ne fonctionne pas parce que je dois encore parcourir toutes les compétences possibles (voir stub_player_skills) et vérifier si un PlayerSkill existe déjà. Imaginez que nous ayons les compétences 1, 2 et 3. Si j'ai les compétences n ° 1 et n ° 3, nous devons remplacer le n ° 2. Je pense que le problème est que j'utilise ActiveRecord pour faire une autre "recherche", est-ce que je devrais simplement parcourir le tableau dans ma logique métier à la place? – Robbie
Je suis désolé, j'ai totalement raté cette partie. Je peux voir ce que vous essayez de faire maintenant ... Je vais réviser mon message. – Coderama
Avec une légère modification, cela a fonctionné et le contrôleur n'a plus besoin de requêtes n pour charger les PlayerSkills. La vue cependant prend toujours des requêtes n parce que je l'appelle ps.object.skill.name; Il me semble que cela peut être une limitation dans la manière dont Rails gère fields_for, ce qui est plutôt regrettable. – Robbie