【发布时间】:2016-04-14 13:17:45
【问题描述】:
这是一个例子:
假设我有一个 Student 对象,它与 ReportCard 对象具有 has_many 关系。 ReportCard 对象有一个名为“graded”的布尔字段,用于标记它们已被评分。所以它看起来像:
class Student < ActiveRecord
has_many :report_cards
end
class ReportCard < ActiveRecord
# graded :boolean (comes from DB)
belongs_to :student
end
现在,假设您要创建一个默认范围,以便如果学生没有评分的 ReportCard,您希望查看所有这些,但如果他们至少有一个评分 ReportCard,您只想查看评分的 ReportCard .最后,假设您按“学期编号”排序。
在 ReportCard 上使用此范围可以正常工作:
scope :only_graded_if_possible, ->(student) { where(graded: true, student: student).order(:semester_number).presence || order(:semester_number) }
但我希望它成为 Student 的默认范围,所以我尝试了:
class Student < ActiveRecord
has_many :report_cards, ->{ where(graded: true).order(:semester_number).presence || order(:semester_number) }
end
但这不起作用。如果整个数据库中只有一个分级报告卡,它不会返回任何报告卡。查看正在运行的查询,首先它运行如下内容:
SELECT report_cards.* FROM report_cards WHERE reports_cards.graded = t ORDER BY semester_number ASC
我想这一定是现在?检查存在查询的一部分,并注意它根本没有过滤学生!因此,如果有一个已评分的 report_card,则检查通过,然后运行以下查询以获取返回的内容:
SELECT report_cards.* FROM reports_card WHERE report_card.student_id = 'student id here' AND report_card.graded = t ORDER BY semester_number
如果学生有评分报告卡,这个查询实际上是正确的,但如果他没有,则它总是空的。
我假设之后可能会添加对 Student 的过滤。所以我试图以某种方式让它立即过滤学生:
has_many :report_cards, ->{ where(graded: true, student: self).order(:semester_number).presence || order(:semester_number) }
这也不起作用,因为这个范围内的“self”似乎不是我假设的 Student 对象,而是所有 report_card id 的列表。这是这个运行的查询:
SELECT report_cards.* FROM report_cards WHERE report_cards.graded = t AND report_cards.student_id IN (SELECT report_cards.id FROM report_cards) ORDER BY semester_number ASC
这甚至不接近正确。我怎样才能让它工作?
我认为真正归结为有人能够将“self”(即当前的 Student 对象)作为参数传递到“has_many”中应用的范围内。也许那是不可能的。
【问题讨论】:
-
你使用的是什么版本的 Rails?
标签: ruby-on-rails ruby activerecord scope has-many