Фильтры каталога: в...
 
Уведомления
Очистить всё

Фильтры каталога: в index восемь if по params. Как это пишут нормально?

5 Сообщения
4 Пользователи
3 Реакции
328 Просмотры
Улугбек Е.
Сообщения: 10
Автор темы
Разобрался с блоками junior-разработчик
Присоединился: 1 год назад
[#116]

Работаю пятый месяц, это первая работа. Rails 8.1, Turbo Frames, база SQLite. Каталог с фильтрами, и экшен index разросся:

def index
  @products = Product.all
  if params[:category].present?
    @products = @products.where(category_id: params[:category])
  end
  if params[:min_price].present?
    @products = @products.where("price >= ?", params[:min_price])
  end
  if params[:max_price].present?
    @products = @products.where("price <= ?", params[:max_price])
  end
  if params[:in_stock] == "1"
    @products = @products.where("stock > 0")
  end
  # и ещё четыре таких же
  @products = @products.order(params[:sort] || "created_at DESC")
end

Ревьюер написал «вынеси фильтры», а куда именно, не сказал. В проекте есть и scopes, и класс ProductSearch, которым никто не пользуется. Как правильно?


4 ответа
Егор64
Сообщения: 30
Читает чужие PR тимлид
Присоединился: 3 года назад

Ревьюер, скорее всего, хотел scopes. Это первый шаг, и для многих проектов он же последний. Каждый scope сам решает, что делать с пустым значением, а контроллер превращается в одну цепочку:

class Product < ApplicationRecord
  scope :in_category, ->(id) { where(category_id: id) if id.present? }
  scope :price_from, ->(v) { where(price: v.to_d..) if v.present? }
  scope :price_to, ->(v) { where(price: ..v.to_d) if v.present? }
  scope :in_stock, ->(flag) { where(stock: 1..) if flag == "1" }
end

@products = Product.in_category(params[:category])
                   .price_from(params[:min_price])
                   .price_to(params[:max_price])
                   .in_stock(params[:in_stock])

Если scope возвращает nil, Rails подставляет all, поэтому условие внутри работает как надо.


Ответ
kostya.sokurov
Сообщения: 73
Держит прод бэкенд-разработчик, senior
Присоединился: 4 года назад

А сортировку из параметров в order напрямую не пропускай, даже если Rails сейчас и отсекает откровенный SQL. Белый список:

SORTS = {
  "new" => { created_at: :desc },
  "cheap" => { price: :asc },
  "pricey" => { price: :desc }
}.freeze

@products = @products.order(SORTS.fetch(params[:sort], SORTS["new"]))

ProductSearch пригодится, когда фильтры начнут зависеть друг от друга или появится полнотекстовый поиск. Пока хватает scopes, не торопись.


Ответ
1 ответ
Давид Г
Присоединился: 10 месяцев назад

Разобрался с блоками тимлид
Сообщения: 7

Автор: kostya.sokurov
Белый список

И ключи из этой же константы удобно отдавать в select на форме, тогда список сортировок живёт в одном месте


Ответ
Улугбек Е.
Сообщения: 10
Автор темы
Разобрался с блоками junior-разработчик
Присоединился: 1 год назад

Сделал scopes как у Егор64 и белый список сортировки, ProductSearch удалил с одобрения ревьюера. Экшен стал на шесть строк. Спросил ревьюера прямо, что он имел в виду: именно scopes, а сортировку он и сам не заметил, так что меня ещё и похвалили) Тест на неизвестную сортировку тоже добавил.


Ответ