1
votes

Rails: Rechercher et filtrer les livres par catégorie

J'ai besoin d'aide, s'il vous plaît. Je suis en train de créer une fonction de recherche avancée pour ma bibliothèque numérique, et je souhaite rechercher des livres par leur nom ou leur description, puis filtrer également les résultats de la recherche par catégorie à laquelle appartiennent les livres.

La base de données est structurée de cette façon: Les livres appartiennent à des sous-catégories et catégories, tandis que les sous-catégories appartiennent uniquement aux catégories. Mais je souhaite filtrer par catégories.

Disons que j'ai un livre intitulé Great Achievers et Great Developers et qu'ils appartiennent au les catégories Achievers et Developers respectivement. Je souhaite que la recherche fonctionne de cette manière: lorsque je recherche à l'aide du mot clé Génial , je verrais les livres Grands succès et Grands développeurs , et quand Je filtre par catégorie Achievers Je ne verrais que Great Achievers .

À l'heure actuelle, ma fonction de recherche avancée peut rechercher des livres par leur nom et leur description, mais ne peut pas filtrer les livres par catégorie dans les résultats de recherche.

Ceci est le code pour le modèle de livre

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

Ceci est le code pour le modèle de catégorie

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

Ceci est le code pour le modèle de sous-catégorie

XXX

Ceci est le code tronqué pour le contrôleur de livres

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

Ceci est le code tronqué pour la fonction de recherche sur la vue d'index des livres

class Category < ApplicationRecord
  has_many :sub_categories
  has_many :books
end

J'ai joint une capture d'écran du journal de ma console lorsqu'une action de recherche est effectuée  entrez la description de l'image ici a>

Veuillez toute forme d'assistance sera très appréciée. Merci.


0 commentaires

3 Réponses :


0
votes

Vous avez besoin d'une jointure (non testée, mais vous avez l'idée):

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

EDIT:

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


2 commentaires

Merci beaucoup pour votre réponse. Dois-je apporter des modifications à mon contrôleur de livres et à ma fonction de recherche de vue index des livres pour qu'ils fonctionnent correctement?


Salut @CAmador, je viens de l'essayer, voici l'erreur que j'ai rencontrée: ActiveRecord :: StatementInvalid in Books # index SQLite3 :: SQLException: nom de colonne ambigu: nom: SELECT "books". * FROM "books" INNER JOIN "categories" ON "categories". "id" = "books". "category_id" WHERE (nom COMME '% soins infirmiers%' OU description COMME '% soins infirmiers%' OU auteur COMME '% soins infirmiers%') ET "catégorie". "Id" =? ORDER BY id DESC, created_at DESC LIMIT? DÉCALAGE ?. Comment résoudre ce problème?



1
votes

La meilleure chose à faire est de trouver les livres qui sont dans la catégorie de filtre. Filtrez ensuite cette collection de livres en fonction du terme de recherche.

Vous pouvez modifier le code du contrôleur de livres comme ci-dessous.

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

Le code tronqué de la fonction de recherche dans la vue d'index des livres peut rester le même

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

Le code du modèle de livre peut également rester le même

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

J'espère que cela vous aidera.

Évaluer cette réponse comme utile si cela peut vous aider, ou commentez la réponse ci-dessous pour plus de précisions .


10 commentaires

Merci beaucoup pour votre réponse. Dois-je apporter des modifications à mon modèle de livre et à mon index de livres fonction de recherche de vue pour permettre de fonctionner correctement?


@PromisePreston, pas besoin de changer quoi que ce soit dans le fichier de modèle de livre. Mettez simplement à jour la méthode d'index à laquelle j'ai répondu dans le contrôleur de livres. Cela devrait fonctionner correctement. Veuillez vérifier.


Salut @dharmesh et @CAmador, je viens d'essayer cette réponse mais j'obtiens cette erreur. NoMethodError dans BooksController # index . 'méthode undefined `recherche' pour # Voulez-vous dire? chaque'. Comment dois-je procéder?


@PromisePreston, Je viens de tester votre exemple dans mon exemple d'application. Pas besoin de changer quoi que ce soit dans le modèle de livre. La fonction de recherche doit rester la même dans la question. Mettez simplement à jour le contrôleur de livre et essayez cette réponse et acceptez la réponse si cela fonctionne correctement.


Salut @dharmesh, je viens de l'essayer maintenant et cela a fonctionné, mais les résultats de la recherche ne filtrent pas encore par catégorie. Il affiche simplement la recherche de livres en fonction de leurs noms, description et auteur sans filtrer les résultats des livres lorsque je sélectionne une catégorie particulière lors de la recherche. Pouvez-vous m'aider s'il vous plaît. Merci.


@PromisePreston Pouvez-vous s'il vous plaît me faire savoir la valeur des paramètres qui est enregistrée dans le journal / console du serveur de rails lors de l'appel?


@dharmesh, je viens de joindre une capture d'écran du journal de la console à la question


@PromisePreston, mise à jour de la condition if dans la réponse. Cela fonctionnerait.


continuons cette discussion dans le chat .


@dharmesh, je rencontre toujours des problèmes avec le filtrage des catégories. Merci beaucoup pour votre aide, je vais continuer cette discussion en chat.



1
votes

La recherche est quelque chose que vous pouvez éviter de faire par vous-même si vous utilisez ransack . Vous pouvez même faire un one-liner dans votre contrôleur avec lui pour obtenir ce que vous voulez:

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

Ensuite, dans vos requêtes, vous devez passer les paramètres [: q] , en effectuant la recherche dont vous avez besoin pour la ressource livres. IE:

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

Vérifiez le correspondants disponibles pour que vous puissiez créer vos filtres comme vous le souhaitez.


0 commentaires