2016-12-10 2 views
2

У меня есть модель «Курс», которая имеет следующие атрибуты;Rails лучший способ для области видимости

Course 
    Price - float 
    Featured - boolean 

Моего вопрос будет следующим, мне нужно 4 списков в моем контроллере, последние курсы, платные курсы, бесплатные курсы и курсы признаков.

Было бы хорошей практикой написать мой контроллер следующим образом?

def index 
    @courses = Course.order(created_at: :desc) 

    @free_courses = [] 
    @courses.map {|c| @free_courses << c if c.price == 0} 

    @premium_courses = [] 
    @courses.map {|c| @premium_courses << c if c.price> 0} 

    @featured_courses = [] 
    @courses.map {|c| @featured_courses << c if c.featured} 
end 

Или проводить консультации отдельно?

def index 
    @courses = Course.order(created_at: :desc) 
    @free_courses = Course.where("price == 0") 
    @premium_courses = Course.where("price > 0") 
    @featured_courses = Course.where(featured: true) 
end 

Я проверил журналы, что первый вариант - более высокая производительность, но я сомневаюсь, что это анти-партнер.

Спасибо за все!

ответ

0

Как правило, плохой практикой является итерация по всем записям в базе данных в Rails (т. Е. Course.map или Course.all) как для производительности, так и для использования в памяти. По мере роста вашей базы данных это становится экспоненциально проблематичным. Гораздо лучше использовать методы Course.where(). Вероятно, вам понадобится порядок сортировки по умолчанию, чтобы вы могли добавить одну строку в своей модели.

default_scope { order(created_at: :desc) } 

Тогда вы можете просто сделать это в контроллере, и они будут иметь вид по умолчанию:

@courses = Course.all 

Я хотел бы также предложить добавить областей для вашей модели для более легкого доступа. Итак, в вашем курсе.гь файл

scope :free -> { where("price == 0") } 
scope :premium -> { where("price > 0") } 
scope :featured -> { where(featured: true) } 

Тогда в вашем контроллере вы можете просто сделать:

@courses = Course.all 
@free_courses = Course.free 
@premium_courses = Course.premium 
@featured_courses = Course.featured 

Эти области также могут быть соединены, если вам нужно объединить тех, так что вы могли бы сделать что-то вроде:

@mixed_courses = Course.premium.featured 

Как пояснили другие, Model.where() выполняет выбор данных, передавая sql внутри where("Write Pure SQL QUERIES HERE"), где в качестве обычных рубиновых перечислимых методов (.map) итерации над массивом, который должен быть создан как объекты ruby. Именно здесь проблемы с памятью/производительностью становятся хитом. Это нормально, если вы работаете с небольшими наборами данных, но что-либо с объемом данных станет уродливым.

+0

Спасибо за ответ –

+0

Мой ответ - «Эти области также могут быть изменены». Опечатка должна быть «Эти области также могут быть заколки». Есть ли что-то в моем ответе, которое не гарантирует рост? благодаря – lacostenycoder

2

Второй подход станет быстрее первого, поскольку размер таблицы курса увеличивается. Первый подход должен перебирать каждую запись в таблице 4 раза. Второй подход создает отношение только записей, которые соответствуют предложению where, поэтому он делает меньше работы.

Кроме того, второй подход имеет преимущество лени. Каждый запрос запускается только во время его использования, поэтому его можно изменить далее по коду. Это более гибко.

Обратите внимание, что это будет улучшение второго подхода к созданию областей на модели курса, которая обрабатывает логику. Например, по одному для курсов, free_courses, premium_courses и отличных курсов. Это имеет преимущество, заключающееся в том, что логика базы данных используется в модели вместо контроллера, где ее можно более легко использовать и поддерживать.

+0

Спасибо за ответ –

1

Второй подход лучше, потому что, когда вы используете метод .where(), вы упорядочиваете запрос в самой базе данных, а не контроллером.

+0

Спасибо за ответ –

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