[英]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 Achievers和Great 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.