Ruby-on-rails 通过关联belongs_to
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4021322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
belongs_to through associations
提问by vinhboy
Given the following associations, I need to reference the Questionthat a Choiceis attached through from the Choicemodel. I have been attempting to use belongs_to :question, through: :answerto perform this action.
鉴于以下关联,我需要从模型中引用QuestionaChoice所附加的Choice。我一直试图用它belongs_to :question, through: :answer来执行这个动作。
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
I am getting
我正进入(状态
NameError uninitialized constant
User::Choice
NameError 未初始化的常量
User::Choice
when I try to do current_user.choices
当我尝试做 current_user.choices
It works fine, if I don't include the
它工作正常,如果我不包括
belongs_to :question, :through => :answer
But I want to use that because I want to be able to do the validates_uniqueness_of
但我想使用它,因为我希望能够做到 validates_uniqueness_of
I am probably overlooking something simple. Any help would be appreciated.
我可能忽略了一些简单的事情。任何帮助,将不胜感激。
采纳答案by stephencelis
A belongs_toassociation cannot have a :throughoption. You're better off caching the question_idon Choiceand adding a unique index to the table (especially because validates_uniqueness_ofis prone to race conditions).
一个belongs_to协会不能有:through选择。您最好缓存question_id打开Choice并向表中添加唯一索引(特别是因为validates_uniqueness_of容易出现竞争条件)。
If you're paranoid, add a custom validation to Choicethat confirms that the answer's question_idmatches, but it sounds like the end user should never be given the opportunity to submit data that would create this kind of mismatch.
如果您有疑虑,请添加自定义验证以Choice确认答案question_id匹配,但听起来最终用户永远不应有机会提交会造成这种不匹配的数据。
回答by Renra
You can also delegate:
您还可以委托:
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
回答by mrm
Just use has_oneinstead of belongs_toin your :through, like this:
只需在您的 中使用has_one而不是,就像这样:belongs_to:through
class Choice
belongs_to :user
belongs_to :answer
has_one :question, :through => :answer
end
Unrelated, but I'd be hesitant to use validates_uniqueness_of instead of using a proper unique constraint in your database. When you do this in ruby you have race conditions.
不相关,但我会犹豫是否使用 validates_uniqueness_of 而不是在您的数据库中使用适当的唯一约束。当您在 ruby 中执行此操作时,您会遇到竞争条件。
回答by Eric Hu
My approach was to make a virtual attribute instead of adding database columns.
我的方法是创建一个虚拟属性而不是添加数据库列。
class Choice
belongs_to :user
belongs_to :answer
# ------- Helpers -------
def question
answer.question
end
# extra sugar
def question_id
answer.question_id
end
end
This approach is pretty simple, but comes with tradeoffs. It requires Rails to load answerfrom the db, and then question. This can be optimized later by eager loading the associations you need (i.e. c = Choice.first(include: {answer: :question})), however, if this optimization is necessary, then stephencelis' answer is probably a better performance decision.
这种方法非常简单,但需要权衡。它需要 Railsanswer从数据库加载,然后question. 这可以稍后通过预先加载您需要的关联(即c = Choice.first(include: {answer: :question}))来优化,但是,如果这种优化是必要的,那么 stephencelis 的答案可能是一个更好的性能决策。
There's a time and place for certain choices, and I think this choice is better when prototyping. I wouldn't use it for production code unless I knew it was for an infrequent use case.
某些选择是有时间和地点的,我认为在原型设计时这种选择更好。除非我知道它用于不常见的用例,否则我不会将它用于生产代码。
回答by MZaragoza
So you cant have the behavior that you want but you can do something that feels like it. You want to be able to do Choice.first.question
所以你不能有你想要的行为,但你可以做一些感觉像它的事情。你希望能够做到Choice.first.question
what I have done in the past is something like this
我过去所做的是这样的
class Choice
belongs_to :user
belongs_to :answer
validates_uniqueness_of :answer_id, :scope => [ :question_id, :user_id ]
...
def question
answer.question
end
end
this way the you can now call question on Choice
这样你现在可以在选择上提出问题
回答by Adam Tanner
It sounds like what you want is a User who has many Questions.
The Question has many Answers, one of which is the User's Choice.
听起来您想要的是一个有很多问题的用户。
问题有许多答案,其中之一是用户的选择。
Is this what you are after?
这是你追求的吗?
I would model something like that along these lines:
我会沿着这些路线建模类似的东西:
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
回答by Michael Melanson
The has_many :choicescreates an association named choices, not choice. Try using current_user.choicesinstead.
将has_many :choices创建一个名为关联choices,不是choice。尝试使用current_user.choices。
See the ActiveRecord::Associationsdocumentation for information about about the has_manymagic.
有关魔法的信息,请参阅ActiveRecord::Associations文档has_many。

