我有一个场景似乎应该是在模型方面解决的事情,但无法找出有效的Activerecord方法的组合。我的数据库的相关部分如下:
Part:
id
part_id
created_at
...
Parttest:
id
part_id
pass (boolean)
created_at
零件可以有许多Parttests,Parttest属于单个零件(在相关模型中设置为has_many和belongs_to)。
在它的生命中 - 一个部件可以多次测试,可以通过,失败,通过等。 使用rails / activerecord我想检索最后(最近的)Parttest是一个传递的Parts的记录集。不应考虑早期的部分测试记录,仅供历史使用。
我尝试过嵌套选择而没有太大成功。我总是可以在控制器中对逻辑进行编码,以检查Part.all.each中的每个Part对象并将它们推送到数组中,但这并不是正确的方法。所有人都非常感谢:)
答案 0 :(得分:0)
编辑:误读了您的帖子,您想要执行类似reference
的操作 Part.joins(:parttests).where(parttests: {pass: true})
将为您提供所有通过考试的部分
尝试Part.joins(:parttests).last.where(parttests: {pass: true})
答案 1 :(得分:0)
使用范围
class Parttest
scope :passed_tests, -> { where(pass: true) }
end
@part = Part.find(1) # Fetch part instance
@part_tests = @part.parttests.passed_tests.last # Fetch its tests
或者在关联中使用条件:
class Part
has_many :passed_tests, class_name: 'Parttest', -> { where(pass: true) }
end
@part_tests = @part.passed_tests.last
现在我已正确理解了这个问题。怎么样?
class Part
has_many :passed_tests, class_name: 'Parttest', -> { where(pass: true) }
scope :with_last_passed_test, -> { joins(:passed_tests).last }
end
Part.with_last_passed_test
答案 2 :(得分:0)
我最初发布了一个冗长的SQL查询作为一个选项,但该建议不是很干净,所以我删除了它。这是一种将其分解为几个小块的方法。
假设我们从这些Parttest行开始:
id part_id created_at pass
1 1 2014-04-26 true
2 1 2014-04-27 false
3 2 2014-04-26 false
4 2 2014-04-27 true
1)首先,我们想要找到每个Part的最新Parttest行。我们可以这样做:
# Parttest model
def self.most_recent
max_rows = select("part_id, MAX(created_at) as max_created_at").group(:part_id)
joins("INNER JOIN (#{max_rows.to_sql}) AS max_rows
ON parttests.part_id = max_rows.part_id
AND parttests.created_at = max_rows.max_created_at")
end
select
会抓住这些值:
part_id created_at
1 2014-04-27
2 2014-04-27
join
会将我们与其他Parttest专栏联系起来:
id part_id created_at pass
2 1 2014-04-27 false
4 2 2014-04-27 true
2)然后我们只想保留通过测试。我们可以这样做:
# Parttest model
scope :passed, -> { where(pass: true) }
将它与(1)结合起来,只有在通过调用传递测试时才能获得最新的测试:
Parttest.most_recent.passed
这只包括从我们的例子中返回这一行:
id part_id created_at pass
4 2 2014-04-27 true
3)然后,为了找到最近测试通过的所有部件,我们可以提供此范围:
# Part model
scope :most_recent_test_passed, -> { where("id IN (?)", PartTest.most_recent.passed.map(&:part_id)) }