Voici le design que j'ai fini par mettre en place. Je suis loin d'avoir une solution complète mais je pense que c'est un bon début.
Modèle de données
Dans mon cas, les utilisateurs doivent être en mesure de construire une liste de tâches où les tâches peuvent avoir différents types et donc attributs. Les tâches peuvent également intégrer des objets supplémentaires. En un sens, c'est similaire à un constructeur de formulaires, bien que je sois confronté à une hiérarchie plus profonde d'objets imbriqués. La clé ici est de s'assurer que votre application back-end n'expose que des objets qui se rapportent à votre domaine d'application (dans le sens de Conception pilotée par le domaine ) afin que votre code côté client ne perde pas de temps à remanier les données après les avoir désérialisées à partir d'un appel serveur et avant de les sérialiser en vue d'une sauvegarde. Dans cette mesure, j'ai dû apporter quelques modifications à ma couche de présentation côté serveur, mais je pense que mon code côté client est plus propre et plus concentré sur le traitement des événements réels de l'utilisateur.
Sérialisation des données
J'ai choisi JSON comme format d'échange de données. Du côté client, j'ai deux fonctions qui gèrent la sérialisation et la désérialisation des données. L'implémentation est assez simple (en partie grâce à certains des changements que j'ai effectués pour exposer les objets du modèle de domaine). J'ai collé une version simplifiée ci-dessous. Le seul problème était que le paramètre _method utilisé par Rails pour gérer les requêtes PUT ne semble pas fonctionner avec un Content-Type JSON. Voir Utilisation de HTTP PUT pour envoyer JSON avec Jquery et Rails 3
var todoList = {};
$.getJSON("/users/123/todolists/456.json", function(data) {
loadTodoList(data);
...
});
function loadTodoList(data) {
todoList = data.todoList;
}
function saveTodoList() {
$.ajax({
type: 'POST',
url: "/users/123/todolists/456",
data: JSON.stringify({ todoList: todoList }),
contentType: 'application/json',
dataType: 'script', // could be "json", "html" too
beforeSend: function(xhr){
xhr.setRequestHeader("X-Http-Method-Override", "put");
}
});
}
Du côté serveur, Rails permet de manipuler facilement le JSON (la sérialisation et la désérialisation du JSON sont effectuées automatiquement et de manière transparente par le framework). J'ai simplement remplacé la méthode to_json() sur mon modèle TodoList pour éviter de transmettre des données inutiles (par exemple les attributs create_at, modified_at). Je devais également m'assurer d'inclure tous les objets imbriqués lors de la récupération de mon objet de niveau supérieur (c'est-à-dire TodoList).
# TodoListsController
def show
@todolist = TodoList.find_by_id(params[:id], :include => [:tasks, ...])
respond_to do |format|
format.json do
render :json => @todolist.to_json
end
end
end
# TodoList model
def to_json
super(:only => :name,
:include => { :tasks => { :only => [:name, :description, ...],
:include => ... }})
end
Persistance côté client
L'objectif est d'éviter de perdre accidentellement les modifications apportées par les utilisateurs qui n'ont pas été enregistrées. Pour l'instant, j'utilise directement le stockage local de HTML5 (variable localStorage), mais je chercherai finalement un plugin jQuery qui gère automatiquement le retour au stockage des cookies si HTML5 n'est pas supporté.
Génération de HTML dynamique
Je m'appuie sur Modèle jQuery pour générer du HTML. La fonction principale du constructeur est de générer dynamiquement du HTML. Ce plugin est donc très utile. J'ai défini des modèles pour tous les blocs de construction de mon modèle de liste de tâches (par exemple, les tâches, les notes, ...). Les modèles sont invoqués chaque fois que de nouvelles instances de ces objets sont créées et doivent être rendues.
Je pense que cela pose la plupart des bases. Le reste est principalement du Javascript pur et dur pour gérer toutes les interactions de l'utilisateur avec le constructeur de formulaire/todoList.