Rails: фильтрация поиска

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

В приложении в основном есть книги, принадлежащие к подкатегориям, и подкатегории, принадлежащие к категориям.

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

Итак, сначала вы создаете категории, а затем создаете подкатегории и выбираете категории, к которым относятся эти подкатегории, а затем создаете книги и выбираете только подкатегории, к которым относится каждая книга, что автоматически помещает эту книгу в категорию, к которой относится эта подкатегория. падает под.

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

Коды следующие

Модель книги

class Book < ApplicationRecord
  belongs_to :category, required: false
  belongs_to :subcategory, required: false

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

Модель подкатегорий

class Subcategory < ApplicationRecord
  belongs_to :category
  has_many :books
end

Модель категорий

class Category < ApplicationRecord
  has_many :subcategories
  has_many :books
end

Контроллер книг (усеченный)

class BooksController < ApplicationController
  before_action :set_book, only: [:show, :edit, :update, :destroy]

  def index
    if params[:category].blank? or params[:category][:id].blank? 
      @books_view = Book.all
    else  
      @books_view = Category.find(params[:category][:id]).books
    end
    @books = @books_view.search(params[:keywords]).paginate(page: params[:page], per_page: 12)
  end
end

Форма поиска страницы указателя книг

<%= form_tag(books_path, method: :get) do %>
      <%= text_field_tag :keywords, params[:keywords], {placeholder: 'eg: Nursing', :class => 'searchForm'} %>
      <%= collection_select :category, :id, Category.all.order('name ASC'), :id, :name,{include_blank: 'Select Category'}, { :class => 'form-control'} %>
    <button type="submit">
      Search
      <%= image_tag("searchIcon.svg", :alt => "search", :class => "") %>
    </button>
  <% end %>

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

Обновить

Я попробовал решение от Dileep Nandanam, обновив Books Controller таким образом.

class BooksController < ApplicationController
    before_action :set_book, only: [:show, :edit, :update, :destroy]

    def index
        if params[:category].blank? or params[:category][:id].blank? 
            @books_view = Book.all
        else  
            @books_view = Book.joins(:subcatagory).joins('catagories on catagories.id = subcatagories.catagory_id').where(catagories: {id: params[:catagory][:id]})
        end
        @books = @books_view.search(params[:keywords]).paginate(page: params[:page], per_page: 12)
    end
end 

Но это действительно не сработало, как ожидалось. Я столкнулся с некоторыми проблемами. Ниже приведен скриншот проблемы.

![NoMethodError in BooksController#index неопределенный метод `[]' для nil:NilClass]1


person Promise Preston    schedule 10.06.2019    source источник
comment
номер строки с ошибкой не подскажешь?   -  person dileep nandanam    schedule 14.06.2019
comment
Прошу прощения за задержку, это номер строки, в которой произошла ошибка @books_view = Book.joins(:subcatagory).joins('catagories on catagories.id = subcatagories.catagory_id').where(catagories: {id: params[:catagory][:id]}). Я также включил скриншот ошибки в обновленный вопрос.   -  person Promise Preston    schedule 15.06.2019
comment
проверьте, равен ли params[:category] нулю, это единственное место, где мы делаем выборку массива, возможно, с нулевым значением. Также используйте gem better_errors для проверки ошибок игрока.   -  person dileep nandanam    schedule 15.06.2019


Ответы (2)


Я считаю, что ваши проблемы исходят из этой конкретной вещи:

class Book < ApplicationRecord
  belongs_to :category, required: false # <= This is wrong
  belongs_to :subcategory, required: false
end

Ответ на ваш конкретный вопрос:

<%= form_tag(books_path, method: :get) do %>
      <%= text_field_tag :keywords, params[:keywords], {placeholder: 'eg: Nursing', :class => 'searchForm'} %>
      <%= collection_select :subcategory, :id, Subcategory.all.order('name ASC'), :id, :name,{include_blank: 'Select Category'}, { :class => 'form-control'} %>
    <button type="submit">
      Search
      <%= image_tag("searchIcon.svg", :alt => "search", :class => "") %>
    </button>
  <% end %>

Но уточним ответ:

Смотри, в твоей абстракции есть большая проблема. Если книга принадлежит как к подкатегории (с subcategory_id), так и к категории (с category_id), у вас действительно нет согласованной структуры данных. Если вы используете реляционную базу данных, вы нарушаете нормализацию БД. Что действительно должно произойти здесь, так это отделить категорию от книги и сослаться на нее через подкатегорию, например так:

class Book < ApplicationRecord
  belongs_to :category, required: false, through: :subcategory
  belongs_to :subcategory, required: false
end
person Michael Kosyk    schedule 10.06.2019
comment
Большое спасибо за ваш ответ. Есть ли способ отфильтровать категорию и подкатегорию, как вы ответили? - person Promise Preston; 11.06.2019
comment
У меня также было это сообщение об ошибке Неизвестный ключ: :through. Допустимые ключи: :class_name, :anonymous_class, :foreign_key, :validate, :autosave, :foreign_type, :depend, :primary_key, :inverse_of, :required, :polymorphic, :touch, :counter_cache, :Optional, :default - person Promise Preston; 11.06.2019

Будьте строги в отношении хранения category_id в подкатегориях и subcategory_id в книгах, но не catagory_id в книгах.

Мы немного модифицируем действие индекса таким образом

class BooksController < ApplicationController
    before_action :set_book, only: [:show, :edit, :update, :destroy]

    def index
        if params[:category].blank? or params[:category][:id].blank? 
            @books_view = Book.all
        else  
            @books_view = Book.joins(:subcatagory).joins('catagories on catagories.id = subcatagories.catagory_id').where(catagories: {id: params[:catagory][:id]})
        end
        @books = @books_view.search(params[:keywords]).paginate(page: params[:page], per_page: 12)
    end
end

и метод поиска становится

def self.search(keywords)
    if keywords
        where('books.name LIKE ? OR book.description LIKE ? OR book.author LIKE ? OR book.abstract LIKE ?', "%#{keywords}%", "%#{keywords}%", "%#{keywords}%", "%#{keywords}%").order('books.id DESC')
    else
        order('books.id DESC')
    end
end
person dileep nandanam    schedule 10.06.2019
comment
Позвольте мне попробовать это сейчас. Большое спасибо - person Promise Preston; 11.06.2019
comment
Добрый день, извините за опоздание. Я попробовал решение, которое вы дали, однако с ним возникли некоторые ошибки. Ошибка NoMethodError in BooksController#index undefined method `[]' for nil:NilClass. Пожалуйста, как мне это исправить? Я также добавил решение в модель книги, но также столкнулся с некоторыми ошибками. Ошибка ActiveRecord::StatementInvalid in Books#index SQLite3::SQLException: нет такого столбца: book.description: SELECT COUNT(*) FROM books WHERE books.isdelete = ?..... Пожалуйста , Как я могу это исправить. Я добавил скриншот к вопросу. - person Promise Preston; 14.06.2019