Étant donné les associations suivantes, je dois référencer le Question
auquel un Choice
est attaché via le modèle Choice
. J'ai essayé d'utiliser belongs_to :question, through: :answer
pour effectuer cette action.
class User
has_many :questions
has_many :choices
end
class Question
belongs_to :user
has_many :answers
has_one :choice, :through => :answer
end
class Answer
belongs_to :question
end
class Choice
belongs_to :user
belongs_to :answer
belongs_to :question, :through => :answer
validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
end
Je reçois
NameError constante non initialisée
User::Choice
quand j'essaie de faire current_user.choices
Cela fonctionne bien, si je n'inclus pas le
belongs_to :question, :through => :answer
Mais je veux utiliser cela parce que je veux pouvoir faire le validates_uniqueness_of
Je néglige probablement quelque chose de simple. Toute aide serait appréciée.
UNE belongs_to
l'association ne peut pas avoir un :through
option. Vous feriez mieux de mettre en cache le question_id
sur Choice
et l’ajout d’un index unique à la table (surtout parce que validates_uniqueness_of
est sujet aux conditions de compétition).
Si vous êtes paranoïaque, ajoutez une validation personnalisée à Choice
qui confirme que la réponse est question_id
correspond, mais il semble que l'utilisateur final ne devrait jamais avoir la possibilité de soumettre des données qui créeraient ce type d'incohérence.
Vous pouvez également déléguer:
class Company < ActiveRecord::Base
has_many :employees
has_many :dogs, :through => :employees
end
class Employee < ActiveRescord::Base
belongs_to :company
has_many :dogs
end
class Dog < ActiveRecord::Base
belongs_to :employee
delegate :company, :to => :employee, :allow_nil => true
end
Il suffit d'utiliser has_one
au lieu de belongs_to
dans votre :though
, comme ça:
class Choice
belongs_to :user
belongs_to :answer
has_one :question, :through => :answer
end
Sans lien, mais j'hésiterais à utiliser validates_uniqueness_of au lieu d'utiliser une contrainte unique appropriée dans votre base de données. Lorsque vous faites cela dans Ruby vous avez des conditions de course.
Mon approche consistait à créer un attribut virtuel au lieu d’ajouter des colonnes de base de données.
class Choice
belongs_to :user
belongs_to :answer
# ------- Helpers -------
def question
answer.question
end
# extra sugar
def question_id
answer.question_id
end
end
Cette approche est assez simple, mais s'accompagne de compromis. Il faut Rails pour charger answer
à partir de la base de données, puis question
. Ceci peut être optimisé ultérieurement en chargeant avec impatience les associations dont vous avez besoin (c'est-à-dire c = Choice.first(include: {answer: :question})
), cependant, si cette optimisation est nécessaire, la réponse de stephencelis est probablement une meilleure décision de performance.
Il y a un moment et un lieu pour certains choix, et je pense que ce choix est meilleur pour le prototypage. Je ne l'utiliserais pas pour le code de production, sauf si je savais que c'était pour un cas d'utilisation peu fréquent.
Donc, vous ne pouvez pas avoir le comportement que vous voulez, mais vous pouvez faire quelque chose qui vous ressemble. Vous voulez pouvoir faire Choice.first.question
ce que j'ai fait dans le passé est quelque chose comme ça
class Choice
belongs_to :user
belongs_to :answer
validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
...
def question
answer.question
end
end
de cette façon, vous pouvez maintenant appeler la question sur Choice
Cela ressemble à ce que vous voulez, c'est un utilisateur qui a beaucoup de questions.
La question a de nombreuses réponses, dont le choix de l'utilisateur.
Est-ce ce que vous recherchez?
Je modéliserais quelque chose comme ça dans ce sens:
class User
has_many :questions
end
class Question
belongs_to :user
has_many :answers
has_one :choice, :class_name => "Answer"
validates_inclusion_of :choice, :in => lambda { answers }
end
class Answer
belongs_to :question
end