Rails 条件更好
Better Where Conditions With Rails
在我的 Rails 4 应用程序中,我做了很多依赖模型的查询。这是代码:
@examination.cities.includes(:translations).each do |city|
Participation.where(exam_center_preference: city.id, payment_status: true, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, payment_status: false, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, examination_id: @examination.id).count
@examination.exam_languages.each do |exam_language|
Participation.where(exam_center_preference: city.id, language_preference: exam_language.id, examination_id: @examination.id).count
end
end
问题是,这段代码生成了太多 SQL 查询,而且看起来效率不高。有没有更好的方法,更好的方法来处理这个问题?
您可以从提取循环内的各种计数查询开始,然后利用 SQL 语言通过单个查询执行计数。
例如,如果你采用这个循环
@examination.exam_languages.each do |exam_language|
Participation.where(exam_center_preference: city.id, language_preference: exam_language.id, examination_id: @examination.id).count
end
并且您应用我 的原则,您可以在单个查询中执行每种语言的计数。
使用单个 SQL 语句无法轻易减少其他查询。例如
Participation.where(exam_center_preference: city.id, payment_status: true, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, payment_status: false, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, examination_id: @examination.id).count
在这种情况下有几种可能的方法。您可以缓存查询,以便它在一个范围内只执行一次。
# the query is performed and cached for 1 minute
Rails.cache.fetch("queries/blabla/paid", expires_in: 1.minute) {
Participation.where(exam_center_preference: city.id, payment_status: true, examination_id: @examination.id).count
}
理想情况下,您应该将这种复杂性隐藏在控制器之外。在控制器中链接大量 ActiveRecord 作用域绝对不是可重用的方法。它还限制了正确测试查询的能力。
更不用说您何时开始将查询与其他层(例如缓存层)混合。您可以考虑 one of these patterns 将您的活动记录链分解为可重用的对象。
在我的 Rails 4 应用程序中,我做了很多依赖模型的查询。这是代码:
@examination.cities.includes(:translations).each do |city|
Participation.where(exam_center_preference: city.id, payment_status: true, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, payment_status: false, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, examination_id: @examination.id).count
@examination.exam_languages.each do |exam_language|
Participation.where(exam_center_preference: city.id, language_preference: exam_language.id, examination_id: @examination.id).count
end
end
问题是,这段代码生成了太多 SQL 查询,而且看起来效率不高。有没有更好的方法,更好的方法来处理这个问题?
您可以从提取循环内的各种计数查询开始,然后利用 SQL 语言通过单个查询执行计数。
例如,如果你采用这个循环
@examination.exam_languages.each do |exam_language|
Participation.where(exam_center_preference: city.id, language_preference: exam_language.id, examination_id: @examination.id).count
end
并且您应用我
使用单个 SQL 语句无法轻易减少其他查询。例如
Participation.where(exam_center_preference: city.id, payment_status: true, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, payment_status: false, examination_id: @examination.id).count
Participation.where(exam_center_preference: city.id, examination_id: @examination.id).count
在这种情况下有几种可能的方法。您可以缓存查询,以便它在一个范围内只执行一次。
# the query is performed and cached for 1 minute
Rails.cache.fetch("queries/blabla/paid", expires_in: 1.minute) {
Participation.where(exam_center_preference: city.id, payment_status: true, examination_id: @examination.id).count
}
理想情况下,您应该将这种复杂性隐藏在控制器之外。在控制器中链接大量 ActiveRecord 作用域绝对不是可重用的方法。它还限制了正确测试查询的能力。
更不用说您何时开始将查询与其他层(例如缓存层)混合。您可以考虑 one of these patterns 将您的活动记录链分解为可重用的对象。