Rails: поиск и фильтрация книг по категориям - PullRequest
1 голос
/ 12 апреля 2019

Мне нужна помощь, пожалуйста. Я создаю функцию расширенного поиска для своей цифровой библиотеки, и я хотел бы искать книги по их именам или описанию, а затем фильтровать результаты поиска по категории, к которой принадлежат книги.

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

Допустим, у меня есть книга под названием Великие достижения и Великие разработчики , и они принадлежат к категориям Отличники и Разработчики соответственно. Я хочу, чтобы поиск работал следующим образом: когда я выполняю поиск по ключевому слову Великий , я вижу книги Великие достижения и Великие разработчики , и когда я фильтрую по категория Достижения Я бы видел только Великие Достижения .

Сейчас моя функция расширенного поиска может искать книги по их именам и описаниям, но не может фильтровать книги по категориям в результатах поиска.

Это код модели книги

class Book < ApplicationRecord
  has_one_attached :upload
  belongs_to :category, required: false
  belongs_to :sub_category, required: false

  def self.search(keywords)
      if keywords
        where("name LIKE ? OR description LIKE ? OR author LIKE ?", "%#{keywords}%", "%#{keywords}%", "%#{keywords}%").order('id DESC')
      else
        order('id DESC') 
      end
    end
end

Это код для модели категории

class Category < ApplicationRecord
  has_many :sub_categories
  has_many :books
end

Это код для модели подкатегории

class SubCategory < ApplicationRecord
  has_many :books
  belongs_to :category, required: false
 end

Это сокращенный код для контроллера книг

class BooksController < ApplicationController
  def index
    @books = Book.search(params[:keywords]).paginate(:page => params[:page], :per_page => 9).order('created_at DESC')
  end

  private
    def set_book
      @book = Book.find(params[:id])
    end

    def book_params
      params.require(:book).permit(:name, :author, :description, :category_id, :sub_category_id, :new_sub_category_name, :upload, :keywords, :deep_keywords)
    end
end

Это усеченный код для функции поиска в представлении указателя книг

<%= form_tag(books_path, method: :get) do %>
    <%= text_field_tag :keywords, params[:keywords] %>
    <%= collection_select :category, :id, Category.all.order('name ASC'), :id, :name,{include_blank: 'Select Category'} %>
    <%= submit_tag 'Search', name: nil %>
<% end %>

Я приложил снимок экрана с моим журналом консоли после выполнения действия поиска enter image description here

Пожалуйста, любая форма помощи будет высоко оценена. Спасибо.

Ответы [ 3 ]

1 голос
/ 12 апреля 2019

Лучше всего найти книги из категории фильтров. Затем отфильтруйте эту коллекцию книг по поисковому запросу.

Вы можете изменить код контроллера книг, как показано ниже.

def index 
if params['category'].blank? or params['category']['id'].blank? 
@books = Book.all 
else 
category = Category.find(params['category']['id']) 
@books = category.books 
end 
@books = @books.search(params[:keywords]).paginate(:page => params[:page], :per_page => 9).order('created_at DESC') 
end

Усеченный код для функции поиска в индексном представлении книг может остаться прежним

<%= form_tag(books_path, method: :get) do %>
    <%= text_field_tag :keywords, params[:keywords] %>
    <%= collection_select :category, :id, Category.all.order('name ASC'), :id, :name,{include_blank: 'Select Category'} %>
    <%= submit_tag 'Search', name: nil %>
<% end %>

Код модели книги также может оставаться прежним

class Book < ApplicationRecord
  has_one_attached :upload
  belongs_to :category, required: false
  belongs_to :sub_category, required: false

  def self.search(keywords)
      if keywords
        where("name LIKE ? OR description LIKE ? OR author LIKE ?", "%#{keywords}%", "%#{keywords}%", "%#{keywords}%").order('id DESC')
      else
        order('id DESC') 
      end
    end
end

Надеюсь, это поможет.

Подпишите этот ответ как полезный, если он поможет, или прокомментируйте ниже ответ для получения дополнительных разъяснений.

1 голос
/ 12 апреля 2019

Поиск - это то, что вы можете избежать самостоятельно, если используете ransack .Вы даже можете использовать в своем контроллере однострочную строку для достижения того, что вы хотите:

def index
    @books = Book.all.ransack(params[:q]).results.paginate(:page => params[:page], :per_page => 9)
end

Затем в ваших запросах вы должны передать params[:q], выполняя любой поискВы должны сделать для ресурса книги.IE:

#params[:q] for books with category_id == 10
{ "category_id_eq": 10 }
#params[:q] for books with name or description or author matching "search"
{ "name_or_description_or_author_matches": "%search%" }
#params[:q] for books with name or description or author matching "search" and category_id == 10
{ "name_or_description_or_author_matches": "%search%", "category_id_eq": 10 }
#params[:q] for books with name or description or author matching "search" and category_id == 10, ordered by created_at
{ "name_or_description_or_author_matches": "%search%", "category_id_eq": 10, "s": "created_at desc" }

Проверьте доступных сопоставителей , чтобы вы могли создавать свои фильтры по своему желанию.

0 голосов
/ 12 апреля 2019

Вам нужно объединение (не проверено, но вы поняли):

def self.search(params)
  books = where(nil)
  keywords = params.dig(:keywords)
  if keywords
    books = books.where("name LIKE ? OR description LIKE ? OR author LIKE ?",
                         "%#{keywords}%", "%#{keywords}%", "%#{keywords}%")   
  end

  cat_id = params.dig(:category, :id)
  if cat_id
    books = books.joins(:category).where(category: {id: cat_id})
  end

  books.order('id DESC')
end

EDIT:

  def index
    @books = Book.search(params).
             paginate(page: params[:page], per_page: 9).
             order('created_at DESC') # You already set order on search
  end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...