Ruby on rails 如何避免Rails中带有参数的范围内的N+1查询

Ruby on rails 如何避免Rails中带有参数的范围内的N+1查询,ruby-on-rails,Ruby On Rails,在这种情况下,我遇到了一个N+1问题: 图书馆有许多程序。现在我想让所有程序都位于某个国家,所以我有一个代码: country = "US" programs = @libraries.includes(:programs).map do |library| library.programs.where(country: country) end 但现在存在N+1问题: Program Load (0.8ms) SELECT "programs".* FROM "programs"

在这种情况下,我遇到了一个N+1问题:

图书馆有许多程序。现在我想让所有程序都位于某个国家,所以我有一个代码:

country = "US"
programs = @libraries.includes(:programs).map do |library|   
  library.programs.where(country: country)
end
但现在存在N+1问题:

Program Load (0.8ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 15], ["country", "US"]]
Program Load (0.4ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 73], ["country", "US"]]
Program Load (0.5ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 27], ["country", "US"]]
Program Load (0.3ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 177], ["country", "US"]]
Program Load (0.3ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 38], ["country", "US"]]
Program Load (0.4ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 51], ["country", "US"]]
Program Load (0.6ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 18], ["country", "US"]]
Program Load (0.3ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 20], ["country", "US"]]
Program Load (0.5ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 42], ["country", "US"]]
Program Load (0.5ms)  SELECT "programs".* FROM "programs" WHERE "programs"."library_id" = $1 AND "programs"."country" = $2  [["library_id", 39], ["country", "US"]]
更新:

我的目的不仅仅是过滤程序,而是使用它。例如:

programs = @libraries.includes(:programs).each do |library|   
  if library.programs.where(country: country).size < 5
    puts "US programs are less than 5 so you can still add"
  end
end
有人知道如何解决N+1问题吗?

您可以将where查询链接到包含,如下所示

programs = @libraries.includes(:programs).where(programs: {country: country})
=> [5, 4, 7, 4, 6, 2, 1]
这将解决N+1问题

更新1:

你可以这样做

programs = @libraries.includes(:programs).where(programs: {country: country}).size < 5 #returns true or false

if programs #true
  puts "US programs are less than 5 so you can still add"
else #false
  #your code
end
它将只执行一个查询并返回每个库的大小。与该条件匹配的程序将作为数组,如下所示

programs = @libraries.includes(:programs).where(programs: {country: country})
=> [5, 4, 7, 4, 6, 2, 1]
现在您可以迭代程序大小数组并执行逻辑

programs_size.each do |ps|
  if ps < 5 #true
    puts "US programs are less than 5 so you can still add"
  else #false
    #your code
  end
end

谢谢Pavan,我的例子可能很简单,所以你用了另一种方式。请看我的更新。@Stephen更新了答案。嗨,Pavan,你的条件是检查所有小于5的集合,但我的示例是每个库,如果小于5,则判断程序。这是不同的。嗨,帕万,首先再次感谢你更新的答案。但是,你能不能不要过滤这些程序?实际上,我将显示所有程序,每个程序可能都有操作按钮。例如,如果美国程序的大小小于5,则显示+US按钮;如果UK程序大小小于5,请显示+UK按钮等@Stephen您只需从上述查询中删除where,并根据您的需要构建逻辑。您能否解释一下您使用此查询库所做的操作。programs.wherecountry:country.size<5?Hi@Pavan,我真正的问题要比我的例子复杂得多,我只是简单明了地解释了这个例子,可能没有真正的意义。我再次更新了示例代码,我认为这更有意义。那么,我将更新适合您的示例的代码