Rails 3

Fin 2008, les développeurs de Merb et Rails ont annoncé qu'ils allaient joindre leurs efforts pour sortir un Rails 3 qui combinerait les avantages de Rails et ceux de Merb. Depuis, nous avons porté beaucoup d'espoirs qui s'annonce très prometteuse, mais qui est également une source de frustration que cette version ne soit pas déjà disponible. Enfin, la semaine dernière, Rails 3 est officiellement sorti en beta (avec les release notes détaillées).

Pour le moment, Rails 3 reste encore le domaine des développeurs aventureux, ceux qui n'ont pas peur de rencontrer des bugs. Par exemple, de nombreux plugins ne sont pas encore compatibles avec Rails 3 (railsplugins.org est une bonne source pour connaître la liste de ceux qui le sont).

Si vous faites parti de cette catégorie, alors deux choix s'offrent à vous. Vous pouvez commencer une nouvelle application avec Rails 3. Le 200ème railscast est un très point de départ pour ça. L'autre choix, plus ambitieux, est de porter une application Rails existante vers Rails 3. Je vous conseille alors de vous faire aider par le plugin rails_upgrade en vous laissant guider par les explications du peepcode Rails 3 Upgrade.

Dans tous les cas, il est intéressant de commencer à se plonger dans les nouveautés de Rails 3. Les articles sur le sujet sont dispersés sur de nombreux blogs, mais des listes permettent de s'y retrouver. Celle de Ruby Inside me semble être la plus complète pour le moment.

Je vous encourage également à participer à l'initiative Give Back to Open Source. C'est très simple : prenez votre plus gros projet Rails, regardez les gems et plugins que vous utilisez, et pour chacun d'eux, contribuez en retour : donnez de l'argent, corrigez un bug, écrivez de la documentation, ou simplement, remerciez son auteur. L'important est de donner en retour.

Madison Street cable car derailed in snow, 1929

Quand on développe une application web, la sécurité est toujours une problématique à prendre au sérieux. Négligez-la et vous pouvez être sûr qu'un jour ou l'autre, un petit malin se fera le plaisir de vous montrer vos failles. Une attaque simple mais très répandue est l'injection XSS (ou Cross-site scripting). Le principe est d'envoyer du code HTML dans un site web pour qu'il soit interprété par le navigateur d'un autre utilisateur. Par exemple, on peut poster la ligne suivante sur un forum pour essayer d'ennuyer les autres utilisateurs :

  1. <script>alert('All your base are belong to us!');</script>

Cette attaque n'est toutefois pas à prendre à la légère. Elle permet par exemple de voler les cookies d'un utilisateur et donc sa session, ou encore de lui faire des actions indésirables sur le site attaqué.

Il est donc nécessaire de se protéger de cette attaque et, rassurez-vous, Ruby on Rails a tout ce qu'il faut pour faire ça simplement. Jusqu'à maintenant, la méthode pour faire ça consiste à indiquer à Rails les chaînes de caractères qui contiennent du contenu manipulé par l'utilisateur et qui pourraient donc être dangereuses. Dans le cas le plus fréquent, une telle chaîne ne doit pas du tout contenir de balise HTML, et on peut alors utiliser le helper h qui transforme les caractères dangereux en entités HTML. Exemple :

  1. Hello <%=h @name %>

Dans le cas contraire où l'utilisateur a le droit d'entrer du texte HTMl enrichi avec des balises HTML, il convient de limiter les balises et attributs autorisés. Le helper sanitize permet de faire ça :

  1. Biographie : <%=sanitize @bio %>

Cela fonctionne très bien, mais il y a toujours le risque d'oublier un h ou un sanitize, ce qui laisserait une porte pour un attaquant. C'est pourquoi il existe des plugins Rails qui favorisent l'approche inverse, à savoir indiquer quelles sont les chaînes de caractères qui sont sûres et d'échapper tout le reste. C'est également l'approche que Rails 3 offrira lors de sa sortie en février 2010.

Dans Rails 3, les chaînes de caractères auront un attribut html_safe, qui indiquera si la chaîne est sûre. Par défaut, l'attribut vaudra false, et cette chaîne sera échappée lors du rendering.

Bien entendu, votre page HTML contient des balises et il est donc nécessaire de pouvoir construire ces balises sans qu'elles soient échappées. Tout d'abord, cette protection ne vise que des contenus venant de l'utilisateur, il est donc inutile d'échapper le contenu "en dur" des vues : seul ce qui se trouvent entre <%= et %> est concerné. Dans l'exemple suivant, le nom apparaîtra bien en gras :

  1. Hello <strong><%= @name %></strong>

Une autre source de contenus légitimes est la génération de code HTML par les helpers de Rails. Heureusement, ces helpers génèrent des chaînes de caractères marquées comme sûres après avoir échappé leurs entrées. Exemple :

  1. <%= tag(:p, "<script>alert('hello');</script>") %>  # => "<p>&lt;script&gt;alert('hello');&lt;script&gt;</p>"

Enfin, il vous reste la possibilité de marquer vous-mêmes les chaînes comme étant sûres. Pour cela, vous pouvez utilisez raw quand vous êtes dans une vue, ou appeler html_safe sur la chaîne si vous êtes dans un helper. Exemple :

  1. <%= raw @site_title %>
  1. def evil_js
  2.   "<script>alert('This site is evil. Mwahahah!');</script>".html_safe
  3. end

Si vous souhaitez en savoir plus, je vous conseille la lecture de SafeBuffers and Rails 3.0 de Yehuda Katz.

AF83 sort une gem que nous utilisons dans nos projets de sites communautaires. Has_media est une bibliothèque pour ActiveRecord, pour gérer les médias dans les modèles avec une simple déclaration :


class User < ActiveRecord::Base
has_one_medium :avatar, :only => :image
end

On ajoute avec cette ligne un "champ" image pour un utilisateur. Il ne reste plus qu'à ajouter un file_field :avatar dans votre formulaire pour que l'image soit associée à l'utilisateur. L'upload est géré par carrierwave. Les méthodes de classe has_one_medium ou has_many_media ajoutent automatiquement les getter et setter pour l'avatar d'un utilisateur.

Les validations sont faites automatiquement selon le type de média défini par l'option :only => :image.

Cas d'utilisation :

# Créer la migration
./script/generate has_media


# Ajouter la gem dans config/environment.rb
config.gem 'has_media'


# Changer les options de has_media dans config/initializers/has_media.rb
HasMedia.directory_path = "media" # Placer les médias dans Rails.root, 'public', 'media'
HasMedia.directory_uri = "/media"
HasMedia.errors_messages = {:type_error => I18n.t('has_media.errors.type_error')}


# Pour le modèle voir plus haut et sur le formulaire
<p>
<%= f.label :avatar %>
<%= f.file_field :avatar %>
</p>
</code>

HasMedia ne gère pas les thumbnails (AF83 utilise une autre application pour cela), mais c'est facilement faisable avec carrierwave.

Plus d'informations : http://github.com/AF83/has_media
Installation : gem install has_media

Pour un de nos projets web, nous allons changer la charte graphique. Le projet en question est codé avec le framework Ruby on Rails, ce qui implique de passer sur chacun des fichiers dans app/views pour vérifier le markup, de modifier les feuilles de styles et de s'assurer que le tout est cohérent sur toutes les pages du site. Comme le site est conséquent, cela risque de ne pas être tout simple. Aussi, ai-je écrit deux scripts pour nous aider.

Le premier script sert à extraire toutes les URL appelées depuis les fichiers de logs Rails :

Le second script permet d'ajouter des commentaires HTML au début et à la fin de chaque fichier dans app/views pour l'identifier depuis le code source de la page HTML générée :

Je pense que cela va nous aider dans notre approche, mais je me demande s'il n'existe pas d'autres trucs pour cela. Avez-vous déjà été confronté à cela ? Si oui, comment vous en êtes vous sorti ?

Ruby gems

af83 utilise Ruby on Rails pour certains de ses projets. De projet en projet, nous prenons des habitudes comme réutiliser certains gems. Je souhaite vous faire partager la liste de ces gems. Cette liste n'a rien d'extra-ordinaire. Ce sont principalement des gems très classiques mais qui méritent d'être mis en avant.

  1. Will Paginate est un plugin Rails pour gérer la pagination. Il est depuis longtemps la référence dans ce domaine et il continue de s'améliorer sans pour autant perdre sa simplicité. Indispensable. http://wiki.github.com/mislav/will_paginate/
  2. Authlogic est une solution complète pour l'authentification et la gestion des utilisateurs. C'est toujours assez délicat de gérer les mots de passe des utilisateurs, les activations de compte, les mots de passe perdus, mais ce gem apporte une manière propre de le faire en gardant une haute exigence de sécurité. http://rdoc.info/projects/binarylogic/authlogic
  3. Acts as state machine offre une solution très appréciable pour gérer des états sur les modèles, et les transitions entre ces états. Rails 3 offrira un module State Machine fortement inspiré de acts as state machine. En attendant, acts as state machine reste indispensable. http://github.com/rubyist/aasm
  4. Friendly_id est un gem bien pratique pour avoir des URL très parlantes. Il permet de créer des slugs et permalinks très facilement en vous évitant les surprises : historique de slugs, mots réservés et support d'unicode sont de la partie. http://norman.github.com/friendly_id/
  5. Thinking Sphinx est une bibliothèque pour connecter ActiveRecord au service de recherche fulltext Sphinx. Son DSL offre de nombreuses possibilités pour faire des recherches avancées sans difficultés. http://freelancing-god.github.com/ts/fr/
  6. HTML Entities est un moyen très simple d'encoder et décoder les entités HTML. http://htmlentities.rubyforge.org/
  7. FasterCSV est une bibliothèque pour manipuler des données au format CSV. Nous l'utilisons sur quasiment tous nos projets pour fournir des exports CSV des données présentes sur le site web. http://fastercsv.rubyforge.org/
  8. rspec est un framework incontournable pour spécifier le comportement de nos applications et nous assurer qu'il n'y ait pas de regressions. http://rspec.info/
  9. factory_girls permet de remplacer les fixtures de Rails, et d'avoir des données pour les specs qui soient faciles à maintenir au fur et à mesure des évolutions. http://github.com/thoughtbot/factory_girl
  10. Pour finir, af83 utilise également has_media, une bibliothèque maison pour la gestion des médias. http://github.com/AF83/has_media

Depuis quelques mois maintenant, af83 utilise la base de données NoSQL MongoDB dans son pôle R&D. Mais pourquoi ce choix ?

Qu'est ce que MongoDB ?

MongoDB est un système de stockage de données NoSQL. En effet, ce n'est pas la peine de faire du SQL pour requêter votre base de donnée MongoDB. On parle alors de base SchemaLess, car il n'est pas nécessaire de faire un script SQL plus ou moins complexe pour créer et définir la structure des données qu'on peut mettre dans notre base. C'est simple, on met juste un énorme Hash.

Le fait de n'avoir des données que sous forme de Hash revient à avoir une base de données dite orienté Documents. MongoDB est donc une base de donnée SchemaLess orientée Documents.

Les bases de données de ce type les plus connues sont CouchDB Riak et MongoDB.

Les plus d'une base de données orienté Documents, SchemaLess ?

La première grande utilité est qu'on est pas obligé d'avoir des scripts de migration pour définir et faire évoluer le format de sa base de données. C'est simple : on crée son objet et on le met dans notre base. On ne se pose pas plus de questions. Cette logique est donc beaucoup plus orientée Objet Dynamique. Un utilisateur peut facilement rajouter par la suite de nouvelles données à cet objet. Avec une base de données SchemaLess, il suffit de modifier son objet, pas sa base de données.

Dans cette même verve, il y a la création de tables. En SQL pur, à chaque nouvelle table, il faut créer un script SQL pour l'ajouter. Là, pas besoin. Tout se fait automatiquement. On peux ainsi facilement switcher entre deux bases de données et créer autant de bases que d'utilisateur.

Le sharding de MongoDB

MongoDB depuis sa version 1.2 intègre une gestion de sharding. L'application de cette gestion permet d'avoir une scalabilité plus importante. Nos données sont toutes cohérentes, car on accède toujours à tout.

Le concept du sharding n'est pas d'avoir plusieurs bases de données en master/master, mais une seule base de donnée qui répartie ses propres données dans les différentes instances. On se retrouve ainsi à posséder certaines données sur une instance et les autres sur une autre.

GridFS

MongoDB embarque avec lui un système de fichiers complet. Ce système est GridFS. MongoDB est limité par document à 4Mo, mais on a vite besoin de stocker des documents plus importants. GridFS permet ça. On stocke donc tout document supérieur à 4 Mo sur le système de fichier GridFS. GridFS permet ainsi d'avoir le sharding sur ses fichiers. On a donc besoin de rsync entre plusieurs machines. GridFS fait le boulot pour soi. On pourrait facilement rapprocher GridFS à Hbase.

Un système de requêtes évolué

Enfin le vrai intérêt de MongoDB selon moi, surtout par rapport à Riak ou CouchDB, c'est sa gestion de requêtages. On peux requêter de façon très fine grâce à une grande quantité de mots-clé. On peux donc faire des requêtes aussi riches qu'en SQL, mais tout ça sur une base de données orientée Documents.

On peux par exemple chercher tous les documents qui possèdent plusieurs éléments dans un tableau

db.things.find( { a: { $all: [ 2, 3 ] } } );

Alors qu'en SQL on aurait plus fait un

SELECT * FROM things WHERE a LIKE '%2%' AND a LIKE '%3%'

Mais cette dernière est finalement incomplète car marchera pour un champs a contenant un array [32] en SQL mais ne fonctionnera pas dans le cas de la requête MongoDB.

On peux aussi faire de la recherche en donnant une fonction Javascript

db.myCollection.find( { $where: "this.a > 3" } );

C'est très modulaire et le nombre de mot clé ne cesse d'augmenter.

Oui, je suis un convaincu de l'utilité de MongoDB. Mais comme toute chose, essayez-le pour vraiment en voir les avantages et vous faire votre propre opinion.

Enfin pour les Rubyistes, vous avez à votre disposition des ODM (Object Document Mapping, l'ORM des base de données orienté Document) complet pour requêter votre base MongoDB : MongoMapper, MongoID et même un adapter DataMapper.

Logo des webhooks

Les webhooks sont un principe tout simple, mais qui offre de nombreuses possibilités pour étendre les fonctionnalités d'un site web. L'idée est vraiment simple : quand quelque chose de particulier se passe sur notre site, on envoie une requête HTTP avec le verbe POST vers une URL donnée. Les webhooks servent donc à notifier des scripts externes à une application web qu'un événement a eu lieu.

Hmmm, ça reste abstrait ? Prenons donc un exemple pour voir pourquoi et en quoi c'est très pratique. Github implémente des webhooks. Vous pouvez configurer pour un de vos dépôts git des URL de callbacks. A chaque fois qu'un commit aura lieu sur le dépôt en question, ces URL seront appelées avec les informations utiles (le nom du dépôt, la révision du commit, etc.). Cela offre de nombreuses possibilités : vous pouvez vous en servir pour déclencher un build sur votre service d'intégration continue (integrity par exemple), mettre à jour la documentation (rdoc.info offre ce service pour les projets ruby) ou encore analyser certaines métriques (Caliper).

Nous voyons que les webhooks peuvent donc servir à notifier très rapidement d'un événement. Mais ce hook peut également déclencher d'autres actions. Par exemple, le service d'intégration continue qui vient de recevoir un hook pourra lancer un build, puis poster le résultat sur un service de microblogging, et celui-ci pourrait alors lancer un autre webhook pour que les utilisateurs qui suivent ce compte soient notifiés, par exemple, en lançant qui script qui enverrait un message jabber, etc. Les webhooks sont cascadables à volonté.

Il existe une autre classe d'utilisation des webhooks : permettre à des script externes d'agir sur le site lui-même. Quand l'URL externe est appelée par un webhook, l'application peut lire le retour et agir en conséquence. Le cas le plus parlant est celui des robots sur Google Wave. Quand un utilisateur écrit dans une wave surveillée par un robot, celui-ci est prévenu par un webhook du contenu qui vient d'être écrit et il peut modifier la wave en réponse. Cela permet d'étendre le fonctionnement de Google wave via l'équivalent de ce que l'on pourrait appeler des plugins, mais avec la grosse différence que le code de ces plugins n'a pas besoin d'être sur le même serveur que la wave elle-même. On peut donc laisser la possibilité à des développeurs externes d'enrichir notre application de manière contrôlée.

Bref, les webhooks me semblent un élément de plus en plus important dans le web temps réel. L'alternative utilisée jusque là, le polling, devient de moins en moins adaptée à des contenus dont le rythme de mise à jour ne cesse d'accélérer. L'exemple de github est d'ailleurs assez symptomatique : il peut se passer plusieurs mois entre 2 commits, mais dès que j'ai commité, je souhaite que l'intégration continue se déclenche au plus vite afin d'être prévenu au plus tôt des regressions que j'aurais pu provoquer avec mon commit.

J'espère que cette introduction aux webhooks vous donnera envie d'appronfondir un peu le sujet, et surtout d'en mettre en place dans vos applications.

Gordon

Le langage de programmation Go est un langage sorti récemment. Pourtant, quand on voit qui est derrière ce langage, je ne peux m'empêcher de penser que ce langage vaut le coup d'être étudié. Le projet a commencé chez Google avec des personnes comme Ken Thompson et Rob Pike. Ils sont tous les deux à l'origine (ou ont contribué fortement) à UTF-8, UNIX, ed, Plan 9, acme... Excusez du peu.

J'ai donc décidé d'essayer Google's Go. Vous pouvez voir mes premières lignes de code sur github : Goldorak Go et goals calendar.

Le but de ce billet n'est pas de vous donner un avis définitif sur ce langage (il me reste encore bien trop de choses à découvrir avant de me permettre de donner un avis, même si je suis pour le moment assez enthousiasmé par ce que j'ai vu), mais de vous donner quelques liens si vous souhaitez aussi découvrir ce nouveau langage.

Tout d'abord, je conseille la lecture du guide d'installation, du tutoriel et du guide Effective Go. Le Go Language Resources est également un point de passage obligé.

Ensuite, on peut assurément commencer à écrire un peu de code, et au fur et à mesure commencer à utiliser des packages de la bibliothèque standard. Par exemple, Michael Hoisie recommande ces 5 packages : bytes, reflect, os, ioutil et vector.

Enfin, j'ai modifié ma configuration de zsh et de vim :

  1. # ~/.zshrc
  2. export GOROOT=$HOME/go
  3. export GOARCH=386
  4. export GOOS=linux
  5. zstyle ':completion:*:(all-|)files' ignored-patterns '*.8'
  1. " ~/.vimrc
  2. set wildignore+=*.6,*.8
  3. au BufRead,BufNewFile *.go set ft=go
  1. " ~/.vim/ftplugin/go.vim
  2. setlocal sw=8
  3. setlocal ts=8
  4. setlocal noet
  1. " ~/.vim/syntax/go.vim
  2. " Ce fichier est fourni avec Go et est également disponible sur :
  3. " http://golang.org/misc/vim/go.vim

Tux et Tix vous saluent

Ça fait un peu plus d'un an que je fais passer des entretiens d'embauche chez af83. C'est toujours un exercice délicat que de juger des compétences techniques et de la motivation d'un développeur sur un simple entretien. D'ailleurs, nous faisons très souvent les entretiens à deux justement pour ça.

Pourtant, je n'ai pas à me plaindre : les candidats retenus ont quasiment tous dépassé mes attentes. Il faut dire qu'il y a souvent un truc qui permet d'affiner son jugement.

Ce truc, je vais vous le dire et vous pourrez vous en servir pour m'impressionner si vous le souhaitez : montrer du code.

Que ce code soit des contributions à un projet sous licence libre, un projet complet ou quelques bouts de code dans un dépôt git, cela ne change pas grand chose. L'important est qu'un bout de code est souvent très révélateur du niveau de la personne qui l'a écrit, et si ce code a été diffusé, cela montre généralement que le développeur se sent plus impliqué par son code. Bref, c'est un très bon indicateur pour juger des deux critères importants : le niveau technique et la motivation.

Mon conseil, si vous cherchez un emploi de développeur, est de passer une soirée à écrire une petite application web (ou n'importe quoi d'autres), puis à diffuser ce code sous une licence libre sur github ou gitorious. Ce sera sûrement bien plus efficace et plus intéressant que de passer la même soirée à écrire des lettres de motivation.

Happy 2010

Nous souhaitons à tous nos lecteurs une bonne et heureuse année 2010.

Hier, j'ai joué avec l'API de backtype. Elle permet de récupérer des tweets, commentaires et autres contenus en rapport avec une recherche. Dans mon cas, je voulais afficher sur les pages d'un site les tweets avec un lien vers cette page. J'aurais pu passer par l'API de recherche de twitter, mais je serais passé à coté de la plupart des tweets, car ceux-ci contiennent des URL raccourcies. Heureusement, Backtype comble ce problème, et il propose gratuitement une API pour faire ça.

Donc, c'est parti. Je crée un compte en 3 clics, et je jette un coup d'oeil à la doc de l'API. Bien, ça a l'air très simple, je ne devrais pas en avoir pour plus d'une heure. Et pourtant, 3 heures plus tard, j'y étais toujours... Rien n'est jamais aussi simple que cela en a l'air.

Mais pourquoi ? Pourquoi faut-il lire une documentation pour utiliser une API Rest toute simple ?

Lors d'OSDC.fr 2009, j'avais parlé de javascript coté serveur. Depuis, 2 mois se sont passés, et même si aucune révolution n'a lieu de ce coté, on sent une vague de fond poindre son nez : Node.js.

Douglas McIlroy résume la philosophie UNIX en :
« This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface. »
Source : Wikipedia

Cette philosophie de faire une seule chose mais de la faire bien pourrait être appliquée au web. Il faudrait sûrement arranger certains points : utiliser des flux HTML en UTF-8 plutôt que des flux textes ascii, remplacer le terme programme par application web, etc. Mais fondamentalement, rien ne nous empêche de concevoir le web de cette façon.

Pourtant, j'ai l'impression que le web actuel s'éloigne de plus en plus de cela pour fournir des applications complètes, complexes, mais qui ont du mal à communiquer entre-elles et dont le passage de l'une à l'autre manque de fluidité.

Bref, je pense que l'on aurait beaucoup à gagner à essayer de se ré-approprier la philosophie UNIX et à l'appliquer au web. Pour cela, il faudrait sûrement inventer des concepts similaires aux pipes UNIX (les WebHooks ?), aux flux standard, au principe "tout est fichier" ("tout est accessible par une URL" ?), aux permissions UNIX, etc. A suivre...

http://dev.af83.com/sites/default/files/logo_blockamp.jpg

L’association Ruby France, l’ESUG , l’INSIA et af83 ont le plaisir de vous annoncer l’organisation d’un BarCamp consacré à Ruby et Smalltalk dans les locaux de l’INSIA à Paris, le samedi 28 novembre 2009.

L’événement est gratuit et ouvert à tous, débutant ou expert. Il suffit de s’inscrire (attention à la limite maximum !) et toutes les explications et les informations pratiques (code d’accès pour entrer…) sont sur la page du wiki BarCamp.

Pour ma part, je vais y aller pour assister aux sessions Ruby, et j'espère pouvoir y discuter des implémentations Ruby (Ruby 1.9, JRuby, Rubinius, MacRuby, etc.), des techniques avancées (Refactoring, Metaprogramming, etc.), découvrir des gems/libs/framework sympas (quelqu'un pour une sessions Ruby + XMPP ?).

Avec Ruby On Rails, il est assez aisé de faire des test unitaires. Il est donc encore plus fortement conseillé de faire des tests dans toutes ses applications Ruby On Rails.

Le soucis quand on teste beaucoupses applications est outre d'avoir moins de bugs, c'est d'avoir des temps de tests qui sont de plus en plus long.

En théorie, il est dit que tant que tous les tests ne font pas plus de 10 minutes, il n'est pas nécessaire de refactorer sont code de tests. Mais il peux quand même être intéressant de suivre le temps d'exécution de chaque tests pour limiter le temps d'un test.

Avec le framework Rspec, il est très simple de découvrir les tests qui sont les plus lent. Le formatteur "profile" (  spec --format profile spec/*_spec.rb ) retourne les 10 tests ( exemples ) qui prennent le plus de temps. Il est donc facile de savoir quels tests refactorer pour améliorer les performances globale de ceux-ci.

Mais avec Test::Unit, la partie était plus compliquée. Heureusement test_benchmarker est là pour nous aider. Grâce à ce gems, un simple require dessus et tout vos tests seront benchmarcké et trié par temps d'execution, par class et surtout par test.

Voici un exemple de sortie de test_benchmarker :