La recherche est un besoin récurrent dans les applications en ligne. Nous avons déjà vu dans un autre article comment utiliser le moteur d’indexation de texte Sphinx. Sphinx a pour avantage d’être très rapide et peu coûteux en ressource car il indexe son contenu. Il ne peut, par contre, faire de la recherche que sur le contenu qui a été indexé et pas sur le plus récent. Il est également à noter que l’implémentation d’une recherche avancée dans l’application n’est pas triviale.
Nous allons donc nous pencher cette fois ci sur le gem Ransack qui a pour avantage de faciliter grandement la mise en place d’un moteur de recherche évolué. Évidemment, Ransack s’avérera moins véloce qu’une solution équivalente basée sur du full-text search puisque ces recherches sont faîtes en temps réel via des requêtes SQL.
Ransack se base sur le gem Squeel, du même auteur, qui étend Arel avec un certain nombre de prédicats permettant l’écriture de conditions à la manière Ruby. Je vous conseille d’y jeter un œil pour votre propre usage au niveau model et controller.
Comme à l’habitude, il vous suffit d’ajouter une ligne à votre Gemfile :
gem "ransack"
La méthode search
est ajoutée aux objets ActiveRecord par Ransack. Cette méthode va permettre de parser les paramètres envoyés par le formulaire pour créer la requête SQL.
Voici un exemple de code controller :
def index
@query = Product.search(params[:q])
@products = @query.result(:distinct => true)
end
On passe donc les paramètres de recherche à la méthode search
qui retourne un objet intermédiaire. Sur cet objet intermédiaire @query
, nous pouvons appeler la méthode result
qui va nous retourner un tableau d’objet AR correspondant à notre recherche.
Notez dans l’exemple que l’on passe true
à l’option distinct
pour s’assurer que nos résultats ne contiennent pas de doublons.
Dans les vues, Ransack met deux choses à notre disposition, un helper pour générer le tag form
ainsi qu’un certain nombre d’attributs virtuels sur notre objet query
utilisé pour générer le form. C’est donc notre objet AR étendu par quelques méthodes spécialisées pour la recherche.
Voyons un exemple simple :
<%= search_form_for @query do |f| %>
<%= f.label :name_cont %>
<%= f.text_field :name_cont %>
<%= f.label :brand_start %>
<%= f.text_field :brand_start %>
<%= f.label :price_lt %>
<%= f.text_field :price_lt %>
<%= f.submit %>
<% end %>
La méthode search_form_for
va créer un formulaire utilisant l’action courante et lui passera les paramètres de recherche.
On utilise ici un certain nombre de prédicats qui nous permettent de rechercher sur des attributs de notre modèle mais en précisant directement, le type de filtrage à opérer.
On souhaite donc que le nom contienne ce qui est entré dans le premier champ, que la marque commence par ce qui est entré dans le deuxième champ et que le prix soit inférieur à ce qui est entré dans le troisième champ.
Vous avez fini, Ransack se charge de tout le reste, vous n’avez plus qu’à afficher vos résultats comme vous le feriez après n’importe quel requête AR.
Comme dit précédemment, Ransack se base sur Squeel et réutilise ses prédicats pour faciliter la mise en place des formulaires de recherche.
Voici la liste des extensions disponibles sur chacun de vos attributs de modèles :
et de leur dérivés :
Ces chaines sont donc à post-fixer au nom de l’attribut concerné.
J’espère donc que cet article vous facilitera la mise en place de vos formulaires de recherche et vous évitera d’avoir à ré-inventer la roue.
L’équipe Synbioz.
Libres d’être ensemble.