Ruby on Rails - Фильтрация записей по выбранным пользователям параметрам - PullRequest
0 голосов
/ 07 января 2019

В моем приложении у меня есть модель Book. У меня в базе данных около 10000 тыс. Записей. В основном, приложение работает так, как пользователь может выбрать опции и получить список книг, которые соответствуют их введенным учетным данным.

Каждый из этих books имеет type, language & genres.

Каждая книга может иметь несколько type, language & genres (как массив)

title: 'Have fun book' 
type: ['pdf', 'paper', 'website']
language: ['Egnlish', 'French', 'German', 'Spanish']
genres: ['comedy']

Мой BooksController:

def book_params
  params.require(:book).permit(type:[], language:[], genres:[])
end

Форма, в которую пользователь может вставить свои учетные данные и отфильтровать книги, выглядит следующим образом:

Book filter form

В настоящее время это то, что я делаю в моем фильтре BooksController to книг:

@book_filter = Book
                .where(type: @book.type)
                .where(language: @book.language)
                .where(genres: @book.genres)

Это нормально работает, но у меня есть несколько проблем с этим. Например, если пользователь не выбирает Тип книги / type или любую другую опцию, вместо получения all я получаю nil, и по этой причине книги не отображаются пользователь.

Я имею в виду, что если опция не была выбрана, либо where для этих опций не получает влияние , либо она проходит all.

Я попробовал это без удачи:

@book_filter = Book
                .where(type: @book.type || '')
                .where(language: @book.language || '')
                .where(genres: @book.genres || '')

Моя вторая проблема заключается в том, что я чувствую, что фильтр мог бы быть написан намного умнее и Rails way .

Заранее спасибо, и любая помощь приветствуется!

Рельсы 5.1

1 Ответ

0 голосов
/ 28 января 2019

В вашем models/concerns создайте module:

module Filterable
  extend ActiveSupport::Concern

  module ClassMethods
    def filter(filtering_params)
      results = self.where(nil)
      filtering_params.each do |key, value|
        results = results.public_send(key, value) if value.present?
      end
      results
    end
  end
end

Включите module в ваш model, как показано ниже:

class Product
  include Filterable
  ...
end

Затем в вашем контроллере выполните:

@products = Product.filter(params.slice(:status, :location, :starts_with))

частный

# A list of the param names that can be used for filtering the Product list
def filtering_params(params)
  params.slice(:status, :location, :starts_with)
end

Причина module в том, что этот код можно использовать повторно и использовать в любой части вашего приложения.

PS: Пожалуйста, имейте в виду, что переменные или модели не совпадают с вопросом, но решение является общим решением, которое может быть реализовано в любом приложении.

...