Comment paginer, trier et filtrer un tableau avec Ajax et Rails
Table des matières
Introduction et avertissements
Avertissement important : comme je n'ai malheureusement plus trop l'occasion de travailler avec Rails ces temps-ci, il est possible que certains points de ce documents soient rendus obsolètes pour les versions les plus récentes de Rails.
L'objectif de ce tutoriel est d'utiliser Ajax et Ruby on Rails pour afficher un tableau de manière dynamique avec les fonctionnalités suivantes :
- pagination : le contenu du tableau peut être réparti sur plusieurs pages ;
- tri : le contenu peut trié selon une colonne du tableau ;
- recherche : les éléments à afficher peuvent être filtrés par une requête.
Une version de démonstration de cette application est visible à l'adresse suivante :
http://dev.nozav.org/ajaxtable/
Il s'agit de quelque chose de très courant lorsqu'on développe une application Web. L'intérêt d'utiliser Ajax est de permettre une interface dynamique qui ne recharge pas l'intégralité de la page à chaque changement. L'intérêt d'utiliser Rails... et bien si vous lisez ceci vous devez déjà être convaincus, mais Ajax est étroitement intégré à Rails, et son utilisation est ainsi grandement facilitée.
Quoi qu'il en soit, le code dans ce tutoriel a été conçu pour fonctionner aussi de manière "classique", c'est à dire en rechargeant l'intégralité de la page, lorsque javascript est désactivé ou non supporté par le navigateur du client. Ceci est très important pour des raisons d'accessibilité.
Le code qui suit est largement issu de plusieurs pages du wiki de rails, et en particulier de How to make a real-time search box with the Ajax helpers, et How to paginate with Ajax. J'ai essentiellement réunis ensemble ces différents éléments en modifiant légèrement le code par endroit.
Et maintenant, les avertissements : je suis loin d'être un expert de Rails, et très loin d'être un spécialiste Ajax. Ce document doit donc être abordé comme une introduction rédigée par un débutant et pour des débutants : le code pourrait sans doute être plus propre et les explications plus détaillées.
Dans tous les cas, n'hésitez pas à me faire parvenir vos remarques, critiques, etc. à l'adresse suivante :
Installation et configuration de l'application
La première chose à faire est d'installer et configurer la base de notre application. Si vous avez déjà effectué ce genre de choses auparavant, vous pouvez sans doute sauter cette section.
Prérequis
Ce document s'applique à une version récente de Rails (au minimum la
2.0) et nécessite l'utilisation d'un SGBD. Dans ce qui suit nous
utiliserons Sqlite
, mais vous pouvez évidemment le remplacer par ce
que vous voulez.
Fichiers
D'abord, nous devons créer le "squelette" de notre application dans le répertoire de notre choix1 :
$ rails ajaxtable $ cd ajaxtable
Depuis la version 2.0 de Rails, les fonctionnalités de pagination ont été intégrées sous la forme de plugins. Le plugin le plus utilisé actuellement se nomme will_paginate, mais je ne suis pas parvenu à faire fonctionner ce tutoriel avec. Nous allons donc installer le plugin "historique" de pagination de Rails, qui se nomme classic pagination :
$ ruby script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination
Comme il s'agit d'une application très simple, nous n'utiliserons qu'un seul modèle, qui représentera les éléments du tableau, et un seul contrôleur pour ces éléments. Les fichiers correspondants sont générés par les scripts Rails :
$ ruby script/generate model Item $ ruby script/generate controller Item
Base de données
Nous devons désormais configurer la source des données de notre
tableau. Par souci de simplicité nous utiliserons Sqlite
associé aux
schémas Rails. Ceci signifie que nous allons décrire notre base de
données à l'intérieur de notre application Rails et laisser ensuite ce
dernier gérer tout ça.
D'abord, il faut configurer la base de données de développement dans
config/database.yml
:
development: adapter: sqlite3 database: db/development.db
Ensuite, nous allons créer la base à parti des outils de migration de Rails :
$ ruby script/generate migration database_creation
Vous devriez maintenant avoir un fichier
db/migrate/001_database_creation.rb
dans lequel nous allons définir
notre première table de la manière suivante :
class DatabaseCreation < ActiveRecord::Migration def self.up create_table :items do |t| t.column :name, :string, :limit => 30 t.column :quantity, :integer, :null => false, :default => 0 t.column :price, :integer, :null => false, :default => 0 end end def self.down drop_table :items end end
Ceci définit une unique table items
avec trois colonnes2 : une
colonne texte nommée name
, et deux colonnes numériques appelées
quantity
et price
(oui, je sais, j'aurais pu trouver un peu plus
original...).
Dès lors, il suffit d'un petit :
$ rake db:migrate
Et vous devriez avoir un fichier db/development.db
qui n'est autre
que la base créée par Rails et contenant votre table items
.
Vous pouvez alors insérer quelques éléments dans votre table histoire
d'avoir quelque chose à afficher pendant le développement de
l'application. Ceci peut être fait à la main ou en sauvegardant les
instructions SQL suivantes3 dans db/dump.sql
:
BEGIN TRANSACTION; INSERT INTO "items" VALUES(1, 'binette', 3, 10); INSERT INTO "items" VALUES(2, 'brouette volante', 2, 60); INSERT INTO "items" VALUES(3, 'salsifis surgelés', 15, 3); INSERT INTO "items" VALUES(4, 'batman', 1, 3000); INSERT INTO "items" VALUES(5, 'saucisse de poisson', 2, 8); INSERT INTO "items" VALUES(6, 'glace à la viande', 9, 9); INSERT INTO "items" VALUES(7, 'arrosoir', 4, 13); INSERT INTO "items" VALUES(8, 'pissenlits confits', 78, 1); INSERT INTO "items" VALUES(9, 'frigo dégivré', 12, 250); INSERT INTO "items" VALUES(10, 'allumettes mouillées', 8, 145); INSERT INTO "items" VALUES(11, 'accordéon déchaîné', 1, 18); INSERT INTO "items" VALUES(12, 'chuchotement sauvage', 5, 7); INSERT INTO "items" VALUES(13, 'escargot hystérique', 8, 13); COMMIT;
Et en faisant un petit :
$ sqlite3 db/development.db < db/dump.sql
Création du modèle
Comme vous le savez sans doute, une application Rails est composée de trois grands types d'éléments : les modèles, les vues et les contrôleurs. Nous allons donc les créer tour à tour.
Le modèle de notre application sera ici très simple. En fait, comme
nous n'avons aucune requête compliquée à transmettre à notre base,
nous allons le laisser tel que généré par Rails lors de
l'installation, c'est-à-dire complètement vide. Nous ne toucherons
donc pas au fichier app/models/item.rb
.
Création de la vue
La vue de notre application sera séparée en trois parties : un layout, une vue et un partiel.
Layout
Le layout est un modèle de page qui sera utilisé pour le rendu de plusieurs vues. Il contient les éléments qui ne varient pas d'une page à l'autre : en-tête et pied de page HTML, menus, éléments de design, etc. L'intérêt d'utiliser un layout ici est plus que limité puisque nous n'avons qu'une page à afficher, mais ce pourrait être utile si nous décidions par la suite d'en ajouter d'autres...
Le layout sera situé dans app/views/layouts/item.rhtml
, avec le
contenu suivant :
<html> <head> <title>Essai de tableau avec Ajax</title> <%= stylesheet_link_tag "style" %> <%= javascript_include_tag :defaults %> </head> <body> <div id="content"> <%= @content_for_layout %> </div> </body> </html>
La chose à noter ici est la balise javascript_include_tag
qui sera
remplacée par des appels aux librairies javascript utilisées par Rails
pour les fonctionnalités Ajax.
À noter également l'instruction @content_for_layout
, qui sera
remplacée par le contenu généré.
Vue
La vue sera utilisée pour rendre une action particulière de notre
contrôleur, lequel sera décrit tout de suite après. Comme il s'agit
d'une action nommée list
de notre contrôleur item
, la vue sera située
dans app/views/item/list.rhtml
.
Le contenu du fichier est le suivant :
<h1>Bienvenue dans ce magnifique tableau</h1> <p>Cette liste est mise à jour en temps de réel depuis la plus large source de données actuellement accessible en utilisant les technologies les plus innovantes associées aux effets graphiques époustouflants du Web 2.0.</p> <p>Mais faites gaffe, y'a plein de bugs.</p> <h2>Et voilà la liste...</h2> <p> <form name="sform" action="" style="display:inline;"> <label for="item_name">Rechercher sur le nom : </label> <%= text_field_tag("query", params['query'], :size => 10 ) %> </form> <%= image_tag("spinner.gif", :align => 'absmiddle', :border => 0, :id => "spinner", :style => "display: none;" ) %> </p> <%= observe_field 'query', :frequency => 2, :update => 'table', :before => "Element.show('spinner')", :success => "Element.hide('spinner')", :url => {:action => 'list'}, :with => 'query' %> <div id="table"> <%= render :partial => "items_list" %> </div>
Le début du fichier n'a rien de très compliqué. Après une courte et stupide introduction, un formulaire de recherche est affiché pour permettre de filter la liste des éléments du tableau selon leur nom.
Ensuite vient une image dont l'identifiant est spinner
et qui n'est
pas affichée par défaut. Cette image sera brièvement affichée
lorsqu'une requête Ajax sera effectuée sur la page, puis masquée à
nouveau lorsque cette requête s'affiche. Vous pouvez trouver un
certain nombre d'images du domaine public à l'adresse suivante :
Vous devez ensuite mettre l'image choisie dans le répertoire public/images
.
L'instruction observe_field
qui suit est un peu moins habituelle. Son
objet ici est de placer un observateur Ajax sur le champ query
. Cet
observateur va vérifier le contenu de ce champ à intervalle régulier
(ici, toutes les 2 secondes comme l'indique le paramètre frequency
) et
réagir si ce contenu a changé depuis sa dernière inspection.
L'action qui doit être exécutée dans ce cas est définie par les paramètres restants :
- update donne l'identifiant de l'élément de la page qui doit être
mis à jour. Ici il s'agit de la <div>
table
qui entoure notre appel au partiel un peu plus loin dans le code ; - url indique l'action à déclencher pour générer le code HTML qui
sera inséré à l'endroit spécifié ci-dessus. Ici, l'action
list
de notre contrôleur prendra en charge toutes les requêtes. - with décrit la manière dont le contenu du champ
query
sera passé à l'action définie par url. Ici nous nous contentons d'ajouter un paramètrequery
à notre requête Ajax avec une valeur égale au contenu du champ. - before indique l'action à exécuter pendant l'intervalle de temps où la requête Ajax est traitée.
- success indique l'action à effectuer lorsque le traitement de la requête Ajax est terminé.
Le résultat de tous ces paramètres est relativement simple. Quand
l'utilisateur saisit quelque chose dans le champ query
, l'observateur
va inspecter cette nouvelle valeur du champ, et générer une requête
Ajax envoyée au serveur selon les paramètres url
et with
. Dès que la
requête est envoyée, l'action before
bascule la visibilité de
l'élément XHTML spinner
, et l'utilisateur voit s'afficher l'image
correspondante. Lorsque la requête a été traitée, l'élément XHTML
table
est mis à jour avec le contenu de la réponse, et l'action
success
cache à nouveau l'image.
Pour information, voici ce que l'instruction observe_field
décrite ici
génère au final :
<script type="text/javascript"> //<![CDATA[ new Form.Element.Observer('query', 2, function(element, value) {Element.show('spinner'); new Ajax.Updater('table', '/item/list', {asynchronous:true, evalScripts:true, onSuccess:function(request){Element.hide('spinner')}, parameters:'query=' + value})}) //]]> </script>
Nous avons délibérément détaillé les différentes options car nous allons les retrouver dans toutes les autres méthode ayant trait à Ajax dans la suite de ce document.
Enfin, pour terminer la description de cette vue, nous avons un appel
à un élément partiel appelé items_list
. Nous décrirons ce concept et
son contenu en détail après avoir configuré notre contrôleur.
Création du contrôleur
Le contrôleur a pour rôle de prendre en charge les différents types de requêtes qui arrivent à notre application pour mettre à jour la vue en appelant le modèle en fonction du type de requête et de ses paramètres.
Notre contrôleur Item
sera ici très simple, et ne contiendra qu'une
action nommée list
. Nous n'implémenterons aucune autre action de type
CRUD (Create, read, update, delete) dans ce tutoriel.
Le contenu de app/controllers/item_controller.rb
est le suivant :
class ItemController < ApplicationController def list items_per_page = 10 sort = case params['sort'] when "name" then "name" when "qty" then "quantity" when "price" then "price" when "name_reverse" then "name DESC" when "qty_reverse" then "quantity DESC" when "price_reverse" then "price DESC" end conditions = ["name LIKE ?", "%#{params[:query]}%"] unless params[:query].nil? @total = Item.count(:conditions => conditions) @items_pages, @items = paginate :items, :order => sort, :conditions => conditions, :per_page => items_per_page if request.xml_http_request? render :partial => "items_list", :layout => false end end end
Ceci mérite quelques explications.
Notre contrôleur ne définit qu'une action, nommée list
. Cette action
traitera l'ensemble des requêtes reçue par notre application.
D'abord, nous définissons une variable items_per_page
qui représente
le nombre de lignes du tableau à afficher sur chaque page.
Ensuite, nous définissons une deuxième variable nommée sort
, en
fonction du contenu du paramètre de requête du même nom. Le case
ici
peut être utilisé pour masquer à l'utilisateur le véritable nom des
champs de notre base de données, ce qui est préférable pour des
raisons de sécurité. La chaîne reverse
dans le paramètre sort
est
utilisée pour indiquer que le tri doit être effectué en ordre inversé.
Une variable conditions
est alors construite si le paramètre query
est
présent dans notre requête. Il s'agit d'une instruction SQL qui sera
utilisée pour filtrer notre requête à la base de données sur le
contenu du champ name
.
Puis nous assignons à la variable @total
le nombre total d'items dans
notre base correspondant aux conditions décrites par conditions
.
Enfin, nous trouvons un appel à l'instruction Rails paginate
. Nous
passons à cette instruction le nom du modèle associé (:items
), un
champ de tri, les conditions devant être appliquées à la requête, et
le nombre d'objets à afficher par page. Et elle nous renvoit
automagiquement un objet de type paginator appelé @items_pages
ainsi
que le tableau des items de la page actuellement sélectionnée (le
numéro de cette page est indiqué de manière transparente par le
paramètre de requête page
). L'objet paginator sera utilisé un peu plus
tard pour afficher les liens de pagination.
Tout ce que nous avons vu jusqu'à présent pour notre contrôleur s'applique à l'ensemble des requêtes reçues, quel que soit leur type. Les types de requêtes HTTP les plus utilisées sont sans doute les traditionnels GET et POST, mais Rails et Ajax utilise également un troisième type nommé XmlHttpRequest4.
Ce type de requête est lancé par javascript, qui l'envoie au serveur via HTTP en arrière-plan, sans que ceci soit visible pour l'utilisateur. L'un des usages de ce type de requête est de récupérer un fragment de page XHTML et de l'utiliser pour mettre à jour, toujours via javascript, une partie de la page affichée par le navigateur, sans avoir à en recharger l'intégralité. Ceci peut donner à l'utilisateur la sensation d'une interface plus dynamique et réactive.
C'est ce que la dernière partie de notre contrôleur traite : il teste
si la requête reçue est de type xml_http_request
5. Si c'est le cas, il
ne génère pas le rendu de l'ensemble de la vue associée à l'action
list
, mais seulement d'un fragment de celle-ci, le désormais célèbre
partiel nommé items_list
.
Ce test sur xml_http_request
est donc le seul élément relatif à Ajax
de notre contrôleur. Ceci est logique car Ajax est avant tout relié à
l'interface de notre application, donc à la vue, et plus
particulièrement au fragment de celle-ci qui sera réellement géré par
Ajax, c'est-à-dire le partiel.
Et ça tombe bien, car c'est justement ce qu'il nous reste à voir.
Création du partiel
Un partiel peut être défini comme un bout de vue utilisé pour générer seulement un fragment de page. Ceci est très utile pour isoler des éléments de vue "répétés" et les rendre réutilisables, et suivre ainsi le principe de Rails "ne pas se répéter" (Don't Repeat Yourself ou DRY). Mais c'est également très utile pour utiliser Ajax.
L'effet des différentes actions Ajax de ce tutoriel sera toujours de rafraîchir l'affichage de notre tableau sans recharger l'intégralité de la page. C'est pourquoi nous allons séparer tous les éléments devant être mis à jour dans un partiel6.
Le nom de fichier d'un partiel commençant toujours par un tiret bas,
il sera donc situé ici dans app/views/item/_items_list.rhtml
.
Son contenu sera le suivant :
<% if @total == 0 %> <p>Aucun objet trouvé...</p> <% else %> <p>Nombre d'objets trouvés : <b><%= @total %></b></p> <p> <% if @items_pages.page_count > 1 %> Page : <%= pagination_links_remote @items_pages %> <% end %> </p> <table> <thead> <tr> <td <%= sort_td_class_helper "name" %>> <%= sort_link_helper "Nom", "name" %> </td> <td <%= sort_td_class_helper "qty" %>> <%= sort_link_helper "Quantité", "qty" %> </td> <td <%= sort_td_class_helper "price" %>> <%= sort_link_helper "Prix", "price" %> </td> </tr> </thead> <tbody> <% @items.each do |i| %> <tr class="<%= cycle("even","odd") %>"> <td><%= i.name %></td> <td><%= i.quantity %></td> <td><%= i.price %></td> </tr> <% end %> </tbody> </table> <% end %>
Quelques explications sont nécessaires. Le partiel inclut la gestion de la pagination et du tri de notre tableau, que nous allons regarder chacun plus en détail.
Assistant de pagination
Nous avons tout d'abord un test déterminant si le nombre total d'objets trouvés est supérieur à zéro. Si c'est le cas, on affiche ce nombre ainsi qu'un paragraphe qui sera vide si la pagination de notre tableau ne comporte qu'une page.
S'il y a plus d'une page de résultats, nous devons afficher les liens de pagination permettant de naviguer d'une page à l'autre. Rails fournit des méthodes très utiles pour générer ces liens, mais nous allons devoir les personnaliser un petit peu. Pour cela, nous allons créer un helper.
Un helper (ou assistant) est une fonction Ruby aidant à générer la vue. L'objectif de créer un helper est de séparer le code de ces fonctions de la vue elle-même, tout en rendant ce code réutilisable par différentes vues.
Nos assistants seront tous situés dans le fichier
app/helpers/item_helper.rb
. Chaque méthode de ce fichier sera
accessible depuis notre vue. Si nous avions voulu rendre ces méthodes
accessibles parl'ensemble des vues de notre application, il aurait
fallu les placer dans application_helper.rb
.
Bref, assez de bla bla, voici le code de notre assistant
pagination_links_remote
:
def pagination_links_remote(paginator) page_options = {:window_size => 1} pagination_links_each(paginator, page_options) do |n| options = { :url => {:action => 'list', :params => params.merge({:page => n})}, :update => 'table', :before => "Element.show('spinner')", :success => "Element.hide('spinner')" } html_options = {:href => url_for(:action => 'list', :params => params.merge({:page => n}))} link_to_remote(n.to_s, options, html_options) end end
Cette méthode prend comme argument un objet de type paginator. Il s'agit d'un objet Rails qui contient toutes les informations relatives à l'état de notre pagination (nombre de pages, page courante, etc.).
Nous définissons ensuite un hash nommé page_options
qui contient un
seul élément window_size
. Ce paramètre indique à Rails le nombre de
pages à afficher autour de la page courante dans les liens de
pagination. Ainsi, si window_size
est égal à un, on aura quelque chose
comme ça :
1 ... 5 6 7 ... 13
Et si window_size
égale deux :
1 ... 4 5 6 7 8 ... 13
Nous pourrions dès lors faire un appel à la fonction pagination_links
,
qui génèrerait directement le code XHTML affichant nos liens. Le
problème est que cette fonction crée des liens "classiques", pas des
liens "Ajax". Nous allons donc devoir redéfinir ces liens nous-mêmes,
ce qui est accompli par la méthode pagination_links_each
.
Cette méthode traverse l'ensemble des pages qui doivent être afichées sous forme de lien et leur applique le bloc qui lui a été passé en argument. Notre bloc définit ici deux types d'options :
- options sert pour la génération des liens Ajax. Son contenu est
très similaire à celui des options de l'élément
observe_field
. La seule réelle nouveauté est l'appel )params.merge
, qui va ajouter les paramètres de la requêtre actuelle au lien généré tout en remplaçant un paramètrepage
éventuel par le numéro de page du bloc. - html_options quant à lui sert à définir les options de génération des liens XHTML "classiques", histoire que la pagination fonctionne si javascrip n'est pas disponible.
Puis, un simple appel à la fonction link_to_remote
génèrera le XHTML
complet correspondant au lien de pagination du numéro de page traité
par le bloc, incluant à la fois la partie javascript et la partie
XHTML href
.
Par exemple, voici ce que l'assistant génère si nous avons deux pages, la première étant actuellement affichée :
1 <a href="/item/list?page=2" onclick="Element.show('spinner'); new Ajax.Updater('table', '/item/list?page=2', {asynchronous:true, evalScripts:true, onSuccess:function(request){Element.hide('spinner')}}); return false;">2</a>
Assistant de tri
Revenons à notre partiel. Après les liens de pagination, nous commençons (enfin) l'affichage de notre tableau. La définition de l'en-tête de la table est un peu compliquée, car c'est là que nous définissons les liens permettant de trier notre tableau selon une colonne ou une autre. Chaque cellule d'en-tête de tableau fait appel à deux helpers.
Le premier assistant sort_td_class_helper
, n'est en rien
obligatoire. Son nunique fonction est d'ajouter un
class="sortup"
si la colonne est celle actuellement
utilisée pour trier le tableau, et un class="sortdown"
si
elle est utilisée pour trier par ordre inverse. La seule utilité de
tout ceci est de permettre, via CSS, d'indiquer à l'utilisateur
quelle est la colonne actuellement utilisée pour le tri.
Le code n'a vraiment rien de passionnant :
def sort_td_class_helper(param) result = 'class="sortup"' if params[:sort] == param result = 'class="sortdown"' if params[:sort] == param + "_reverse" return result end
Nous avons ensuite un second assistant, nommé sort_link_helper
.
def sort_link_helper(text, param) key = param key += "_reverse" if params[:sort] == param options = { :url => {:action => 'list', :params => params.merge({:sort => key, :page => nil})}, :update => 'table', :before => "Element.show('spinner')", :success => "Element.hide('spinner')" } html_options = { :title => "Trier selon ce champ", :href => url_for(:action => 'list', :params => params.merge({:sort => key, :page => nil})) } link_to_remote(text, options, html_options) end
Cet assistant est en définitive très similaire à
pagination_links_remote
, vu précédemment. Il prend deux arguments :
- text, qui est juste le texte affiché comme titre de colonne et lien ;
- param, qui est le nom du paramètre de requête associé à cette colonne.
Les deux premières lignes définissent une nouvelle variable, key
, qui
reçoit le contenu de l'argument param
, c'est à dire la clé de tri. La
chaîne _reverse
est ajoutée à cette clé si param
est déjà la clé de
tri. Ceci sert à implémenter le tri par ordre croissant et
décroissant : si l'utilisateur sélectionne un lien de tri, le tableau
sera trié selon la colonne correspondante, par ordre croissant ; si il
sélectionne alors à nouveau le même lien, le tri se fera par ordre
décroissant, etc. Si vous ne trouvez pas ces explications très
claires, jetez un oeil au contrôleur.
Le reste de la fonction définit les options passées au link_to_remote
final. Tout ceci est très similaire à ce que nous avons vu pour
pagination_links_remote
:
- options est un hash utilisé pour le lien Ajax javascript. Il
contient l'
url
de l'action générant le nouveau XHTML, l'identifiant de l'élément devant être mis à jour, et les actionsbefore
etsuccess
permettant de montrer/cacher l'imagespinner
; - html_options est un hash utilisé pour le lien HTML classique. Il
génère le contenu de l'attribut
href
grâce à la fonctionurl_for
de Rails.
Voici ce que l'assistant renvoit s'il est appelé avec les arguments "Quantité" et "qty" :
<a href="/item/list?sort=qty" onclick="Element.show('spinner'); new Ajax.Updater('table', '/item/list?sort=qty', {asynchronous:true, evalScripts:true, onSuccess:function(request){Element.hide('spinner')}}); return false;" title="Sort by this field">Quantité</a>
Corps du tableau
La fin de notre partiel affiche le contenu proprement dit de notre
tableau, un objet par ligne. La seule chose pouvant être notée est
l'utilisation de la fonction Rails cycle
, qui va automatiquement et
alternativement ajouter un attribut "odd" ou "even" comme classe de
style pour les lignes du tableau, ce qui peut être utile pour
améliorer l'affichage en alternant les couleurs de ligne.
C'est fini !
Nous avons désormais passé en revue tous les éléments de notre application. En théorie vous devriez pouvoir voir le résultat en lançant le serveur WebRick intégré à Rails et en vous connectant sur :
J'espère que ce document aura pu vous être utile. Dans tous les cas n'hésitez pas à me faire parvenir vos retours via l'adresse donnée dans l'introduction.
À propos de ce document
Ce document est publié sous licence Creative Commons Attribution.
Merci à Nicolas St-Laurent, Rachel McConnell et Michel Loiseleur pour leurs remarques judicieuses.
Merci à Juan Lupión pour la traduction espagnole de ce document.
1. Les instructions en ligne de commande sont présentées dans le cadre d'un environnement GNU/Linux.
2. En fait, notre table aura quatre colonnes, car un champ id
est
automatiquement ajouté par Rails.
3. Si vous utilisez MySQL comme SGBD, la syntaxe correcte est INSERT
INTO items VALUES (1, 'hoe', 3, 10);
4. En fait, XmlHttpRequest n'est pas réellement un nouveau type de requête HTTP. Il s'agit d'une requête GET ou POST traditionnelle envoyée et traitée par javascript de manière non-synchrone.
5. L'instruction request.xml_http_request?
peut être abrégée en
request.xhr?
6. On aurait pu envisager d'autres manières de faire. En particulier
on aurait pu créer une nouvelle action (par exemple ajax_list
)
pour traiter les requêtes de type xml_http_request
, et une vue
associée sans partiel. L'un des problèmes de cette méthode est
qu'une grande part du code d'ajax_list
aurait été identique à
celui de list
.