2015-01-21 2 views
1

В моем приложении 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 и, похоже, unefficient. Есть ли лучший подход, лучший способ справиться с этим?

+0

Результат операции 'count' не сохраняется в любой переменной. В чем причина этого? А второй блок не закрывается. Вставить правильный код, чтобы понять, что вы пытаетесь сделать, было бы лучше. – Rodrigo

+0

Я редактировал код. Я могу привести результаты операций подсчета в переменную, но уменьшает ли число SQL-запросов? – msdundar

ответ

1

Вы можете начать с извлечения различных запросов count внутри циклов и использовать язык 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 

и применить принцип I detailed in this answer, вы можете выполнить подсчет для каждого языка в одном запросе.

Другие запросы не могут быть легко уменьшены с помощью одного оператора 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, чтобы разложить ваши активные цепочки записей на объекты многократного использования.

Смежные вопросы