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

时间:2019-04-12 10:10:19

标签: ruby-on-rails search

请给我一些帮助。我正在为我的数字图书馆构建高级搜索功能,我想通过书籍的名称或描述来搜索书籍,然后还根据书籍所属的类别过滤搜索结果。

数据库的结构是这样的:书籍属于子类别和类别,而子类别仅属于类别。但是我想按类别过滤。

比方说,我有一本书叫 Great Achievers Great Developers ,它们属于 Achievers Developers 强>分别。我希望搜索以此方式进行:当我使用关键字 Great 进行搜索时,我会看到 Great Achievers Great Developers 这本书,以及何时我按类别成就进行过滤,我只会看到伟大成就者

现在,我的高级搜索功能可以按图书的名称和描述搜索图书,但不能在搜索结果中按类别过滤图书。

这是图书模型的代码

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 个答案:

答案 0 :(得分:1)

最好的办法是找到过滤器类别下的书籍。然后根据搜索词从该藏书中进行过滤。

您可以按以下方式修改图书控制器代码。

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 :(得分:1)

如果您使用ransack,则可以避免自己进行搜索。您甚至可以在控制器中使用单线来实现所需的功能:

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],对图书资源进行任何所需的搜索。即:

#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" }

检查available matchers,以便您可以根据需要构建过滤器。

答案 2 :(得分:0)

您需要加入(未经测试,但您知道了):

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

编辑:

  def index
    @books = Book.search(params).
             paginate(page: params[:page], per_page: 9).
             order('created_at DESC') # You already set order on search
  end