将'where'子句与方法结合使用

时间:2018-02-13 10:25:06

标签: ruby-on-rails ruby scope

在我的应用中,Team belongs_to :hunt。确认Hunt后,所有关联的团队都准备就绪。

这是我team.rb文件中的一个示例,我使用ready?方法检查team.hunt是否已确认。

#team.rb

def ready?
  hunt.confirmed? ? true : false
end

我希望在team.rb文件中设置一个范围,以便我可以致电Teams.all.ready.count来显示准备就绪的团队数量。

如何编写方法或范围来实现上述行为,而无需向数据库添加任何内容或迭代数组等?

2 个答案:

答案 0 :(得分:5)

更新

感谢@ TomLord的洞察力,你宁愿做下面的解决方案1而不是解决方案2.此外,添加示例SQL以显示比较。

解决方案1 ​​

class Team < ApplicationRecord
  belongs_to :hunt
  scope :ready, -> { joins(:hunt).where(hunts: { confirmed: true }) }
end

用法:

Team.ready # or: Team.all.ready
# SELECT  "teams".* FROM "teams" INNER JOIN "hunts" ON "hunts"."id" = "teams"."hunt_id" WHERE "hunts"."confirmed" = ? LIMIT ?  [["confirmed", "t"], ["LIMIT", 11]]

或者,解决方案2

class Team < ApplicationRecord
  belongs_to :hunt
end

class Hunt < ApplicationRecord
  scope :confirmed, -> { where(confirmed: true) }
end

用法:

# you can also move the logic below as a method/scope inside `Team` model (i.e. as `ready` method/scope)

# Example 1 (using JOINS):
Team.joins(:hunt).where(hunts: { id: Hunt.confirmed })
# SELECT  "teams".* FROM "teams" INNER JOIN "hunts" ON "hunts"."id" = "teams"."hunt_id" WHERE "hunts"."id" IN (SELECT "hunts"."id" FROM "hunts" WHERE "hunts"."confirmed" = ?) LIMIT ?  [["confirmed", "t"], ["LIMIT", 11]]

# Example 2 (same as Example 1 above but faster and more efficient):
Team.where(hunt_id: Hunt.confirmed)
# SELECT  "teams".* FROM "teams" WHERE "teams"."hunt_id" IN (SELECT "hunts"."id" FROM "hunts" WHERE "hunts"."confirmed" = ?) LIMIT ?  [["confirmed", "t"], ["LIMIT", 11]]

答案 1 :(得分:1)

解决方案:如果Hunts#confirmed是数据库列:

class Team < ApplicationRecord
  belongs_to :hunt
  scope :ready, -> { joins(:hunt).where(hunts: { confirmed: true }) }
end

在这种情况下,Team.ready将返回ActiveRecord::Relation

解决方案:如果Hunts#confirmed?不是数据库列:

class Team < ApplicationRecord
  belongs_to :hunt
  scope :ready, -> { includes(:hunts).select(&:ready?) }
end

在这种情况下,Team.ready将返回Array

您需要知道第二个解决方案是循环遍历每个调用ready?的团队记录,而第一个解决方案正在执行数据库查询。首先是效率更高。