Rails

Rails 3 vient de sortir. Je vous encourage à lire l'annonce de la sortie sur le blog officiel, Riding Rails si vous ne l'avez pas déjà fait. Pour les nouvelles applications, il n'y a pas de doutes à avoir : Rails 3 est la route à suivre. Mais pour les applications existantes qui utilisent actuellement Rails 2.3, qu'en est-il ? C'est ce que nous allons voir en quelques questions-réponses.

Ai-je intérêt à passer à Rails 3 ?

Oui, Rails 3 apporte de nombreuses améliorations, et à peu près n'importe quelle application va tirer parti de l'une ou l'autre de ces améliorations. Par exemple, la protection par défaut contre les attaques XSS est un grand pas en avant et va simplifier la vie des développeurs. Rails 3 est également plus performant et permet de remplacer plus facilement ActiveRecord par un autre ORM. Bref, les raisons ne manquent pas de passer à Rails 3.

Puis-je passer dès aujourd'hui à Rails 3 ?

Cela dépend des projets. Rails 3 a été bien testé au cours des derniers mois avec 4 versions beta et 2 release candidates, il n'y a pas de problème de ce coté là. Mais passer à Rails 3 ne se fait pas magiquement. Il faut prendre le temps de découvrir la nouvelle version et migrer son application. Cela prend un peu de temps (de quelques jours à quelques semaines, selon la taille de l'application). Il faut donc voir si l'intérêt de passer à Rails 3 est suffisant pour justifier de passer ce temps, puis planifier cette migration, si possible lors d'une période calme.

Et pour les gems/plugins ?

La plupart des gems courants ont des branches sur leur dépôt pour fonctionner avec Rails 3. Des versions stables de ce plugin sont sorties ou vont sortir dans les jours à venir. Vous pouvez vérifier sur le site RailsPlugin.org que les gems que vous utilisez sont compatibles avec Rails 3.

Que faire si une gem n'est pas compatible avec Rails 3 ?

Si la gem n'est plus maintenue, c'est peut être l'occasion de passer à une gem équivalente plus évoluée. Vous pouvez aussi décider de reprendre le projet à votre compte en contactant l'auteur initial.

Si la gem est maintenue mais n'est pas encore fonctionnelle avec Rails 3, vous pouvez aider son auteur de différentes façons :

  1. Ouvrir un ticket sur le bug tracker du projet
  2. Suivre les développements en cours, les tester et remonter les problèmes
  3. Participer au développement en proposant des patchs, voir en créant une branche de code Rails3 spécialement pour l'occasion.

Pour une gem critique, une possibilité peut être de sponsoriser le passage à Rails à son auteur ou à un expert Rails 3.

Je suis décidé à passer à Rails 3, comment je fais ?

La première chose est de migrer vers la version la plus récente de Rails 2.3. La version 2.3.9 va sortir (demain si tout va bien), et permettra de migrer en douceur vers Rails 3. Si vous utilisez des API dépréciées, vous serez prévenu dans les logs. Cela vous permet de préparer une partie du terrain avant le grand saut. Ensuite, vous pouvez utiliser le plugin Rails upgrade pour vous aider à migrer, en suivant les explications de Jeremy McAnally.

Je vous conseille également la lecture de The Rails 3 Upgrade handbook. Le temps gagné grâce à sa lecture remboursera largement les quelques dollars qu'il coûte. Pour ceux qui aiment les vidéos, les 3 Railscasts valent également d'être regardés : partie 1, partie 2 et partie 3.

J'ai un dernier conseil pour la route : utilisez une branche séparée dans votre dépôt git/svn pour faire la migration. Vous aurez probablement besoin d'aller voir plusieurs fois votre application avant la migration et les changements faits depuis si vous rencontrez un point de blocage.

Et pour apprendre Rails 3, quelles ressources sont à ma disposition ?

Certains ont été plus rapides que moi, je vais donc me contenter de donner deux liens :

Sachez également qu'un livre en français est en cours de rédaction et devrait sortir dans les semaines à venir.

Et pour les autres questions ?

Vous pouvez poser votre question en commentaire de ce billet ou sur http://questions.rubyfr.org/.

We have been chasing a bug for quite a long time that made our lives miserable, and our client, very unhappy: When submitting a large form, intermittently the post data is broken (basically only the the first parts of the submitted form data get to Rails). The bug is caused by an incorrect implementation of parsing multipart/form-data in Rack 1.0 and earlier. This is the commit that fixes the issue : http://github.com/rack/rack/commit/a9440bc752be9b3093669614c6b56bf78d592958 you can also look at the added test case to try and reproduce the error.

We are without doubt not the first ones to fall on this, but as finding the bug was very, very hard. I am posting this as a public service hoping someone down the line will have an easier time finding the cause... the solution is easy. Either upgrade Rack to at least 1.1 or patch lib/rack/utils.rb. Also updating Ruby on Rails to > 2.3.6 will solve this as it has a dependency on Rack 1.1

The symptoms can vary, and what makes this bug very very hard to find is that it needs a lot of parameters to manifest itself. You might get validation errors on you models, or missing required parameters at the controller level: or just some unexpected behavior (Not tested, but might result in corrupted uploads). Basically what happened is that when the body data of a post is longer then 16384 and a multipart boundary is found at precisely 16384 bytes... the parser will return with therefor only the first parts parsed. So first, you need to have a huge form, now imagine the form represents something in your database, and you change the data: you need your new data to make the boundary arrive at precisely the slicing point. Considering that each browser may have a different size of boundary, the same change to the same data will not reproduce the error between two different browsers. Also because this executes inside the Application Controller at Racks level, you will find that the app's logs are going to be of very little service. We had to go wireshark on this bug, and follow the post data through all the levels to find where it broke. And we got lucky: we found offending POST data while testing... So basically you might find yourself with an application where from time to time, in what seems to be a completely random way, you will find fields missing from the POST data in production... but reproducing this on test servers might prove very very hard.

Note: this bug is not Rails specific and will happen with any framework using Rack. So just to help people find this: Broken form data on Sinatra, ruby corrupted post, big form fails intermittently with rack. Uploading Files randomly fails Ruby on Rails. Missing Post Data Ruby. Ruby multipart bug. Rails multipart problem.

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.

Mise-à-jour : le Rails 3 Upgrade Handbook est un guide PDF qui vous guide dans votre migration vers Rails 3. Il coûte 12$, mais il les vaut. Vous y trouverez toutes les informations utiles, y compris certaines qui sont très difficiles à trouver ailleurs.

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

Logo
Chaque semaine, je publie une liste de liens vers des billets de blog, des articles et des annonces qui me semblent intéressants et en rapport avec l’activité d’AF83. N’hésitez pas à proposez vos liens. Voici la sélection de cette semaine :
OS & Navigateurs

    Logo
    Chaque semaine, je publie une liste de liens vers des billets de blog, des articles et des annonces qui me semblent intéressants et en rapport avec l’activité d’AF83. N’hésitez pas à proposez vos liens. Voici la sélection de cette semaine :
    Campagne Microsoft

    Logo
    Chaque semaine, je publie une liste de liens vers des billets de blog, des articles et des annonces qui me semblent intéressants et en rapport avec l’activité d’AF83. N’hésitez pas à proposez vos liens. Voici la sélection de ces dernières semaines :
    Conditions d'utilisation