Paris on Rails 2008

Ouverture de session

Commentaires récents

Syndication
Flux XML

[Résolu] Ruby, Array et tris sur plusieurs éléments

[Résolu] Ruby, Array et tris sur plusieurs éléments
Posté par Kobra le Vendredi, 8 Août, 2008 - 1:43pm. Débuter avec Rails

Bonjour bonjour!

Voici mon problème :
J'ai une liste d'éléments (ça, ça fonctionne! youhou!)
Lorsque je supprime un élément (en AJAX), je souhaite utiliser Script.aculo.us et faire un petit BlindUp sur l'élément supprimé.
Ça aussi ça marche, mais j'ai un peu magouillé : Je stock l'item supprimé dans un flash, et je l'ajoute aux items récupérés via un find. En simplifié, ça donne ça :


items = Item.find(:all)
if flash[:deleted_item]
items << flash[:deleted_item]
end

Il me suffit ensuite de repérer l'item supprimé, de lui faire un <li> personnalisé (genre <li id="deleted">) et d'appliquer mon effet. Bon, si une solution plus propre existe, je suis ouvert à toutes critiques.

Reste que ma liste est triée (ben oui, ce serait trop facile sinon). Si je n'avais pas cet item supplémentaire, je ferai un :order => "" dans mon find() et le tour serait joué. Mais je ne peux pas le faire.

Voici donc ma question : Comment faire un tri sur plusieurs éléments?

Cas concret :
Chaque item a une priorité et un statut.
Je souhaite avoir le tri selon la priorité, puis le status en desc, puis l'id.

J'ai fait pas mal de recherche sur les méthodes sort et sort_by, mais je suis bloqué.
Je sais trier sur deux éléments, mais sans pouvoir préciser l'ordre croissant et décroissant (list.sort_by {|item| [item[:prio], item[:statut]]}) et je sais trier sur un élément dans l'ordre décroissant (list.sort {|a, b| b.statut <=> a.statut}), mais je ne sais pas comment combiner les deux...

Une idée encore plus magouilleuse m'est venue en rédigeant ce post : Je pourrais stocker ma liste telle qu'elle était avant suppression, comme ça pas besoin de faire joujou avec sort...

Any ideas?
Merci pour votre aide

Florent



[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | sujet précédent | sujet suivant | envoyer par email ]

Options d'affichage des commentaires
Sélectionnez la méthode d'affichage des commentaires que vous préférez, puis cliquez sur "Sauvegarder" pour activer vos changements.

Sujet: 
Array et tris sur plusieurs éléments
Auteur: 
gemsFinder
Date: 
Ven, 08/08/2008 - 19:10

Bonjour, peut être que je n'ai pas tout compris, mais primo je ne vois pas pour quelle raison tu utilises flash pour stocker un objet (d'autres ressources sont la pour ça).

secondo, je ne vois pas de problème car ton fameux objet intrus, est déjà dans le résultat de ton find. Donc tu appliques un order a ton find , et c'est fait, tu as ta liste triée selon les critères que tu auras précisé.

C'est peu être pas un tri sur un Array mais ça marche et c'est propre


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Oup's
Auteur: 
Kobra
Date: 
Mer, 27/08/2008 - 13:45

Salut gemsFinder,

Je suis vraiment désolé, mais je n'avais pas vu ton post... Avec 19 jours de retard, j'y réponds donc :)

Alors pour le primo : J'utilise flash parce que je ne souhaite garder mon objet que pour l'action suivante. Il me semblait que c'était le principe du flash. Mais s'il y a plus performant, je suis bien évidemment preneur.

Pour le secundo : l'objet qu'il me faut garder n'est pas dans mon find car il vient d'être supprimé dans l'action précédente. Cependant, j'ai besoin de le garder et de le positionner correctement dans ma liste pour lui affecter un effet de "disparition".

En tout cas, merci d'avoir pris le temps de me répondre, et encore désolé de ne pas l'avoir vu tout de suite.


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Bon, pour info, mon idée de
Auteur: 
Kobra
Date: 
Ven, 08/08/2008 - 16:13

Bon, pour info, mon idée de garder l'ancienne liste en flash fonctionne bien. Pour ce qui est de la mémoire utilisée par les flash, je ne suis pas un expert, mais je ne pense pas que ce soit trop trop gourmand...
Quoiqu'il en soit, si quelqu'un saurait me dire comment utiliser sort tel que je le voulais, je suis preneur, pour ma culture G, et puis ça servira peut être à d'autres développeurs.

Bonne fin de journée :D


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Test rapide
Auteur: 
jasperiel
Date: 
Lun, 18/08/2008 - 00:36

> je sais trier sur un élément dans l'ordre décroissant
> (list.sort {|a, b| b.statut a.statut}), mais je ne sais pas
> comment combiner les deux...

Alors tu sais comment on fait :)

list.sort {|a, b| tmp = (b.truc a.truc
(tmp == 0) ? (b.machin a.machin) : tmp }

Ca trie d'abord sur un critère puis l'autre :)

Sinon, tu recodes toute une fonction de tri.
J'ai pas vraiment fait gaffe à la perf ici.
Dis-moi si ça marche (j'ai même pas testé mais ça devrait) !


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Ouaaa, costaud le
Auteur: 
Kobra
Date: 
Mar, 19/08/2008 - 09:44

Ouaaa, costaud le code!!
J'essaye ça dès que j'ai un moment. Ce qui me manque, c'est quelques notions ruby... :s (Faut dire que mon bouquin rails reste très discret sur les bases de ruby)

Que fait cette ligne exactement?
(tmp == 0) ? (b.machin a.machin) : tmp
une boucle? Genre tant que tmp != 0, on tri sur "machin"? Pourqoi le ": tmp"? Un bouquin sur ruby à me conseiller? :D

En tout cas, merci.

Florent


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
crazy one-liners
Auteur: 
jasperiel
Date: 
Mer, 20/08/2008 - 15:54

Ah, alors déjà désolé, l'opérateur de comparaison n'est pas passé.
Il faut mettre "<=>" entre les deux.

Ensuite, "test ? vrai : faux" est un "opérateur ternaire", hérité du C. Si (tmp == 0) alors renvoyer (la comparaison a,b) sinon (tmp).

Bref, c'est un "if then else". Normalement on recommande de faire du code lisible et pas cryptique, mais ici c'est vraiment un truc "basique" et au final on n'est intéressé que par le tri.
Moi je mets plutôt un concept algo par ligne, si on relit mon code on se dira "ouais, là il trie" et on passera vite à la suite, parce que c'est pas important. Et si le problème vient du tri, on ira voir une ligne et pas se demander si les 10 ou 20 autres sont impliquées.

Pourquoi tmp, c'est simple : tu vois que j'en ai besoin 2 fois et j'ai pas envie de le calculer deux fois, alors je stocke.
J'aurais pu mettre

((a.truc <=> b.truc) == 0) ? (b.machin <=> a.machin) : (a.truc <=> b.truc)
A toi de voir, mais moi je me suis dit que le cas le plus courant est "la plupart des objets sont déjà bien triés par la première condition" : si tu tolères 2 calculs quand ils sont différents, ce serait bête de faire 90% du temps 2 fois le même.

Si tu me disais : ma liste est déjà triée sur le premier critère (qui reste le plus important), je veux la trier sur le second, alors cette écriture serait probablement pas plus mal car tu économises en RAM.

Fais tes choix.


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Bonjour jasperiel, Encore
Auteur: 
Kobra
Date: 
Mer, 27/08/2008 - 14:00

Bonjour jasperiel,

Encore merci pour toutes ces explications, c'est un plaisir de te lire :)

Je n'ai pas beaucoup pratiqué le C, et en plus, ça remonte à 4 ans. Donc j'avais un peu oublié la syntaxe test ? vrai : faux.

J'ai pu tester ton code et tout marche très bien (même si personne n'en doutait!). Je pense en effet que l'écriture utilisée est optimisée dans ce cas précis. Un grand merci donc :)

__________

Ecriture utilisée pour mon test (Ça servira peut être à d'autre) :

users = User.find(:all)
users.sort! {|a,b| tmp = (a.firstname b.firstname)
(tmp == 0) ? b.name a.name : tmp}

Comparaison avec le SQL :
SELECT firstname, name FROM users ORDER BY firstname, name DESC;


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
order by SQL
Auteur: 
jasperiel
Date: 
Jeu, 28/08/2008 - 14:07

Merci :)

Je pensais que c'était un traitement complexe (ou sans passer par la BDD, puisque tu parlais de garder des données en local), mais si c'est juste pour un petit cas comme ça, ActiveRecord sait très bien le faire.
users = User.find(:all, :order =>"firstname, name DESC")

Lire la doc
http://api.rubyonrails.org/classes/ActiveRecord/Base.html
:order - An SQL fragment like "created_at DESC, name".


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
Je me suis mal exprimé
Auteur: 
Kobra
Date: 
Jeu, 28/08/2008 - 14:35

Salut,

Excuse moi, en effet, pour le cas simple comme celui-ci, j'aurais utilisé :order.

Le code que j'ai présenté dans l'exemple ci-dessus était juste pour faire le test du tri.

Mais si j'ai fait ce post pour connaitre les secrets du tri selon ruby, c'est que dans mon cas :
- J'ai un liste d'élément avec chacun un lien pour les supprimer
- Lorsque je clique sur le lien, j'appelle l'action delete qui va me supprimer mon élément de la liste (en AJAX siouplay :)).
- Du coup, quand je mets à jour ma liste, l'élément n'y figure plus. Or, pour pouvoir lui affecter un effet de disparition tout droit sorti de script.aculo.us, il faut que mon élément existe, et qu'en plus il soit au bon endroit dans ma liste (sinon, ça risque de faire suspect). Mon action delete passe donc en paramètre l'objet supprimé, que j'ajoute à la liste, laquelle je trie selon les mêmes critères que l'affichage normal via find(:order). Je mets un id à mon objet supprimé et je lui applique l'effet.

Il y a sans doute d'autre façon de faire, comme appliqué l'effet avant d'appeler l'action (je ne suis pas très doué en javascript), ou passer la liste complète dans un flash (ce que j'ai fait en attendant ta réponse).

Voilà voilà :)


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Sujet: 
AJAX or not AJAX ?
Auteur: 
jasperiel
Date: 
Jeu, 28/08/2008 - 18:33

Bon, je vais parler de ton problème, puis de conseils génériques sur le Javascript dans ce qu'on appelle "le Web 2.0" (laissez-moi rire).

POUR TON PROBLEME

> Du coup, quand je mets à jour ma liste, l'élément n'y figure plus.

Aaaah je vois. En fait tu recharges toute la liste quand tu supprimes un seul élément. C'est un peu "overkill", et certainement pas ce que tu as envie de faire pour une liste qui compte plein d'éléments... ou des éléments complexes et longs à calculer.

L'idée, c'est que quand tu génères ta liste, et le lien/bouton "effacer cet élément", tu connais déjà l'ID. Il ne te reste qu'à utiliser l'option "si la requête réussit, applique l'effet delete sur mon objet de départ".
Je ne peux pas trop te sortir tout ça de mémoire, mais c'est dans la doc prototype/scriptaculous, et encore mieux, probablement dans la doc de Rails dans les link_to_remote et autres.

Tu peux même retrouver ton ID subtilement (et donc faire une seule fonction JS qui s'utilise partout) en parcourant le DOM : par exemple, ton lien est probablement dans un conteneur (TR ou DIV par exemple), il suffit donc de passer "this" en argument à une fonction qui serait du genre
function(lien) {lien.up().destroy()}
en faisant ton effet etc...

> Or, pour pouvoir lui affecter un effet de disparition tout droit
> sorti de script.aculo.us, il faut que mon élément existe,
Il existe, puisque tu l'as déjà affiché.

> Mon action delete passe donc en paramètre l'objet supprimé,
> que j'ajoute à la liste, laquelle je trie selon les mêmes critères
Ne le fais pas ici, puisque tu peux mieux faire, mais avec un problème similaire tu pourrais aussi faire un before_filter pour préparer tes données et ton action juste avant de lancer l'action qui modifiera tes données de manière irrécupérable.
Lire la doc d'ActiveController.

> Il y a sans doute d'autre façon de faire, comme appliqué l'effet
> avant d'appeler l'action (je ne suis pas très doué en javascript),
Pas avant, mais "onSuccess".

Je me trompe peut-être sur les noms, mais les concepts existent. Ça fait un moment que je n'ai plus développé comme ça, personnellement.

CONSEILS UTILES POUR TOUT DEV AJAX/JS

Au passage, j'enjoins tous les développeurs Web/AJAX/JS à réfléchir avec attention à ces trois points :
- d'abord, est-ce que j'ai quelque chose qui marche SANS AJAX ?
- ensuite, est-ce que l'AJAX a une valeur ajoutée ?
Est-ce pratique ? Est-ce que mon utilisateur comprend l'interface ?
- enfin, si le type a désactivé le JS dans son navigateur,
peut-il utiliser mon site sans autres problèmes que "cosmétiques" ?

Ça c'est pour la philosophie. Pour le côté technique, maintenant, les questions à se poser sont :
- ai-je vraiment besoin d'une requête au serveur ?
- de quelles données je dispose, côté client ?
- est-ce que je n'aurais pas par hasard déjà tout ce qu'il me faut dans le DOM ?

On se rend compte qu'enchaîner des appels Prototype down(), up(), et même rien qu'avec les standards parent(), children(), on peut récupérer quasiment tout ce qu'on voulait au départ.

Parfois, on est tenté d'écrire et générer des IDs uniques etc, et c'est pas si nul, mais le plus souvent on s'en sort rien qu'en connaissant son contexte et en spécifiant des classes CSS : non seulement c'est propre, générique et optimisé, mais en plus on se retrouve avec une hiérarchie nickel et une CSS toute prête pour faire un site magnifique et customisable jusqu'au bout des ongles !


LE MOT DE LA FIN

Vous allègerez ainsi le nombre de lignes de code, les complexités et le temps de développement, de maintenance, de lisibilité, des facteurs d'erreurs, de sécurité...
tout en améliorant votre compatibilité aux standards et entre navigateurs, sans parler de la charge de votre serveur, tant au niveau processeur que bande passante.
Tout le monde est gagnant : vivent les Best Practices :)


[ Vous devez vous connecter ou vous enregistrer pour écrire des commentaires | envoyer par email ]

Nouveaux liens

Sondage
Lorsque je développe avec Ruby on Rails c'est principalement sous:
Linux
37%
Mac OS X
30%
Windows
32%
(Free|Open|Net) BSD
1%
Autre...
1%
Nombre de votes: 374

Qui est en ligne
Il y a actuellement 1 utilisateur et 58 invités en ligne.

railsfrance.org - communauté francophone des utilisateurs de Ruby on Rails
[ Hébergement et ressources techniques gracieusement fournis par la SSLL Nuxos Group ]