简体   繁体   English

Rails:按类别搜索和筛选书籍

[英]Rails: Search & Filter Books by Category

I need some help please. 我需要一些帮助。 I am building an advanced search feature for my digital library, and I would like to search books by their names or description and then by also filter the search results by the category which the books belongs. 我正在为我的数字图书馆构建高级搜索功能 ,我想通过书籍的名称或描述来搜索书籍,然后还按照书籍所属的类别过滤搜索结果。

The database is structured this way: Books belongs sub-categories and categories, while sub-categories belongs to the categories only. 数据库的结构是这样的: 书籍属于子类别和类别,而子类别仅属于类别。 But I want to filter by categories. 但是我想按类别过滤。

Let's say I have a book named Great Achievers and Great Developers and they belong to the categories Achievers and Developers respectively. 假设我有一本书,名为《杰出成就者》和《 杰出 开发者》 ,它们分别属于“ 成就者”和“ 开发者 ”类别。 I want the search to work this way: when I search using the keyword Great I would see the books Great Achievers and Great Developers , and when I filter by category Achievers I would see only Great Achievers . 我希望搜索以这种方式工作:当我使用关键字Great进行搜索时,我会看到书籍Great AchieversGreat Developers ,并且按类别Achievers进行过滤时,我只会看到Great Achievers

Right now my advanced search feature can search for books by their names and descriptions, but cannot filter the books by category in the search results. 现在,我的高级搜索功能可以按书籍的名称和描述搜索书籍,但不能在搜索结果中按类别过滤书籍。

This is the code for the book model 这是书籍模型的代码

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

This is the code for the category model 这是类别模型的代码

class Category < ApplicationRecord
  has_many :sub_categories
  has_many :books
end

This is the code for the sub-category model 这是子类别模型的代码

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

This is the truncated code for the books controller 这是书籍控制器的截断代码

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

This is the truncated code for the search feature on the books index view 这是书籍索引视图上搜索功能的截断代码

<%= 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 %>

I have attached a screenshot of my console log when a search action is done 完成搜索操作后,我已附加了控制台日志的屏幕截图 在此处输入图片说明

Please any form of assistance will be highly appreciated. 请任何形式的协助将不胜感激。 Thank you. 谢谢。

The best thing is to find the books that are under filter category. 最好的办法是找到过滤器类别下的书籍。 Then filter from that books collection based on the search term. 然后根据搜索词从该藏书中进行过滤。

You can modify the books controller code as below. 您可以按以下方式修改书本控制器代码。

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

The truncated code for the search feature on the books index view can remain the same 图书索引视图上搜索功能的截断代码可以保持不变

<%= 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 %>

The code for the book model can also remain the same 书籍模型的代码也可以保持不变

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

I hope this helps. 我希望这有帮助。

Upvote this answer as useful if it helps, or comment below the answer for more clarification. 如果有帮助,则将该答案评价为有用的,或在答案下方进行评论以进一步说明。

Searching is something that you can avoid doing on your own if you use ransack . 如果使用ransack ,则可以避免自己进行搜索。 You can even do a one-liner in your controller with it to achieve what you want: 您甚至可以在控制器中使用单线来实现所需的功能:

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

Then in your requests you have to pass the params[:q] , doing whatever search you need done for the books resource. 然后,在您的请求中,您必须传递 params[:q] ,对图书资源进行所需的任何搜索。 IE: 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" }

Check the available matchers so you can build your filters as you wish. 检查可用的匹配器,以便您可以根据需要构建过滤器。

You need a join (untested, but you get the idea): 您需要加入(未经测试,但您知道了):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM