Ruby on rails Rails 3-嵌套选择和";。最后一句话;

Ruby on rails Rails 3-嵌套选择和";。最后一句话;,ruby-on-rails,ruby,ruby-on-rails-3,activerecord,chaining,Ruby On Rails,Ruby,Ruby On Rails 3,Activerecord,Chaining,我有一个场景,似乎应该在模型方面解决一些问题,但无法找到一个有效的Activerecord方法组合。my db的相关部分如下所示: Part: id part_id created_at ... Parttest: id part_id pass (boolean) created_at 一个零件可以有多个零件测试,而零件测试属于一个零件(在相关模型中设置为多个零件测试) 在它的生命周期中,一个零件可以被多次测试,并且可以通过、失败、通过等等。 使用rails/activerecord,我希

我有一个场景,似乎应该在模型方面解决一些问题,但无法找到一个有效的Activerecord方法组合。my db的相关部分如下所示:

Part:
id
part_id
created_at
...

Parttest:
id
part_id
pass (boolean)
created_at
一个零件可以有多个零件测试,而零件测试属于一个零件(在相关模型中设置为多个零件测试)

在它的生命周期中,一个零件可以被多次测试,并且可以通过、失败、通过等等。 使用rails/activerecord,我希望检索最后一次(最近一次)Parttest通过的部件记录集。零件试验的早期记录不应考虑在内,仅供历史使用


我试过嵌套选择,但没有多大成功。我总是可以在控制器中编写逻辑代码来检查Part.all.each中的每个Part对象,并将它们放入一个数组中,但这似乎不是正确的方法。非常感谢所有帮助:)

编辑:误读了你的帖子,你想这样做吗

Part.joins(:parttests)。其中(parttests:{pass:true})
将为您提供所有通过测试的部件

使用作用域尝试
Part.joins(:parttests).last.where(parttests:{pass:true})

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

我最初发布了一个很长的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) 首先,我们要为每个零件查找最新的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
# Parttest model
scope :passed, -> { where(pass: true) }
选择
将获取以下值:

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
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
# 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)) }

仅供参考。。。您可以执行
order(在::desc创建)
而不是传递显式字符串。您的作用域中还有一个语法错误。它缺少一个
——已修复。@Mohamad-我可能误解了你的解决方案,但它不起作用。我无法调用Part.parttests,因为parttests不是Part类的方法。上面的代码不会给我parttest,而不是通过测试的部分吗?(这是我想要的零件,不是零件测试)@SG84看我的答案!这是marknach的回答,不是我的。我添加了我自己的。此外,由于海报编辑了该代码,该代码还有另一个语法错误<代码>部件是多元化的。它应该是
部分
。我想编辑一下。我认为OP想找到最近部分测试通过的部分——而不是最近每一篇文章中通过的部分测试——这是正确的——我只想考虑最近的部分测试。@ SG84:我已经更新了我的答案。试试看。“这应该行得通。”穆罕默德-谢谢你在这方面的帮助。您上面的最后一次编辑看起来是正确的,我理解(我想)它应该做什么,但是我在类中得到了两行的语法错误。“语法错误,两行都出现意外的'\n',应为=>”,所以我想可能对新的lambda语法不满意吧?我使用的是Ruby2和Rails3.2。16@SG84不客气。我认为在Rails3.x上不能使用这种语法。试试这个:
有很多:通过测试,…,>条件:“pass=true”
-在这里阅读更多:如果你发现其中的答案有帮助,你介意标记一个接受的答案吗?干杯