Préparation de Paris on Rails 2007
Richard Piacentinia débuté l’organisation de l’édition 2007 de Paris on Rails qui est, comme son nom l’indique, une conférence sur Ruby on Rails.
Je n’avais pas peu me rendre à la première édition en novembre dernier mais j’ai eu l’occasion de rencontrer Richard quelques semaines avant lors d’un séminaire sur le web 2.0 et je me réjoui de pouvoir être présent cette année. On se dirige vers une organisation sur 2 jours et chose importante à un prix toujours abordable (en particulier pour les privés), si vous voulez suivre l’évolution de l’organisation ou avez des suggestions, n’hésitez pas à vous rendre sur le forum dédié.
Mais pas d’inquiétude je vous en reparle bientôt.
En passant j’en profite pour rappeler la prochaine réunion de romandie.rb qui se tiendra ce jeudi et qui aura pour thème une introduction à RoR (non ce n’est pas moi qui m’y colle).
Site officiel de Ruby en français
Le site officiel de Ruby, ruby-lang.org, est maintenant disponible en français. Je trouve que c’est une bonne nouvelle pour sa visibilité puisque même si la documentation n’est pas encore disponible dans notre langue, la présentation de la philosophie du langage et du message pour « vendre » celui-ci est un point positif.
Ruby On Rails est ce qu’il vous faut !
Ruby On Rails est un framework de développement qui a la cote et c’est tant mieux ! Je suis tombé dedans il y a deux ans et il est au cœur de la stratégie de ma société, Liquid Concept, depuis plus d’une année maintenant. Je constante que nous sommes de moins en moins seul dans le paysage Romand à faire ce choix et la création du Ruby User Group pour cette région est un signe que le langage gagne en popularité et reconnaissance ; car si beaucoup le découvre avec RoR, c’est bien Ruby qu’ils adoptent.
Avec le développement de notre plateforme d’hébergement pour les sites de nos clients et ma participation au développement de Globalize j’ai aujourd’hui l’expérience et le recul nécessaire pour pouvoir dire que nous avons fait le bon choix. En cas de besoin vous savez d’ailleurs où me trouver mais en attendant je vous conseil la lecture de cet excellent article d’Ib Com.
Ruby User Group pour la Suisse Romande
C’est en novembre dernier que la création d’un RUG (Ruby User Group) pour la Suisse Romande a été lancé à l’initiative de Guillaume Cottenceau et c’est hier soir, mardi 13 janvier, que la première réunion a eu lieu dans les locaux de MNC à Lausanne. Nous étions 14 pour à cette occasion et j’ai pu ouvrir les feux avec une présentation de Ruby avant un souper auquel je n’ai malheureusement pas pu participer.
Je reviendrai sur ma présentation plus loin mais pour commencer je peux dire que je suis content d’avoir participé à cette soirée qui a réuni déjà un grand nombre de personne ; l’ambiance était bonne et nous avons pu prendre un premier contact intéressant (je regrette d’ailleurs de ne pas avoir eu l’occasion de prolonger mes discussions lors du souper). Je renouvellerai cette expérience avec plaisir.
Pour en revenir à ma présentation, je devais faire un tour d’horizon de Ruby afin d’en montrer les particularités. J’avais prévus quelques slides d’introduction puis l’utilisation de la console interactive pour parler du langage lui-même. Cette approche était intéressante mais pose quelques problèmes ; je n’ai pas pu tenir le timing car je suis souvent allez beaucoup trop loin dans le détail et je n’ai donc pas fait la présentation jusqu’au bout, ce dernier constat est bien dommage car la partie manquante montrait des choses importantes et spécifiques à Ruby. De plus le temps passé à taper du code n’est tout de même pas négligeable. Il faudra donc que je révise ma copie pour une prochaine fois et réserver la console pour répondre aux questions. Enfin, cet exercice est nouveau pour moi mais j’espère pouvoir le renouveler car même si je ne suis pas tout à fait satisfait du résultat j’ai apprécié pouvoir le faire et la prochaine sera assurément meilleur. A se sujet, je vais essayer de trouver le temps pour retravailler cette présentation afin d’être mieux préparé et avoir un modèle si je doit en faire une autre (Ruby On Rails, Globalize, … ?).
Si vous habitez en Suisse Romande ou en France voisine et que Ruby vous intéresse je vous invite à nous rejoindre sur la liste de diffusion.
Rails 1.2.2 et petite note sur Globalize
La Version 1.2 de rails est sortie il y a maintenant plusieurs semaines, voici la 1.2.2 après que la 1.2.1 ai suivi de quelques heures sa grande soeur, ces versions mineurs ne corriges que quelques petits problème, pas besoin de s’étendre dessus plus que ça.
Au sujet de Globalize plusieurs nouvelles têtes ont été intégrée ces derniers temps. Nous sommes en train de préparer une release pour la version 1.2 de rails, tout les testes passent mais il nous reste à faire quelques mises à jour dans la documentation. Je vous tient au courent mais ça ne devrais pas tarder.
Nous préparons également l’intégration de nouvelles fonctionnalités, Saimon doit ajouter son système alternatif de storage et il faudrait vraiment que je merge l’extension développé par Liquid Concept dans le trunk ce que je n’ai pas encore eu le temps de faire. J’espère pouvoir m’y mettre bientôt.
Rails 1.2, quoi de neuf ?
Avec l’arrivée de cette nouvelle version de Ruby on Rails nous avons droit à notre lot de nouveautés, je ne vais pas reproduire le changelog ici mais voici les innovations majeurs de cette mouture, pour le détail, direction le site de développement.
ActiveRecord
- Ajout de la possibilité de passer un Hash en paramètre à la méthode find pour l’option conditions. Chaque clef du Hash correspond à un attribut et ils sont joint par des AND.
- Ajout de la méthode find_or_initialize_by_X qui complète find_or_create_by_X en retournant un nouvelle objet si la recherche ne donne pas de résultat mais sans le sauver.
- Passé un record ou une liste de record à une conditions extrait directement les id.
Model.find(:all, :conditions => ['item_id IN (?)', items])
Model.find(:first, :conditions => ['item_id = ?', item])
- Autorise niq => true avec une association has_many :through.
- Il est maintenant possible d’ajouter un record à une association has_many :through avec les méthodes <<, push et concat en créant le record de jointure.
- Ajout du support de delete à l’association has_many :through.
- L’association has_one support le paramètre dependent avec les options destroy, delete, et nullify.
- Il est possible d’obtenir un lock exclusif sur un enregistrement en utilisant le paramètre lock des méthodes de recherche ou avec la méthode lock! d’un record.
ActionPack
- Il est maintenant possible d’accéder aux attributs avec RJS.
page['foo']['style']['color'] = ‘red’ # => $(‘foo’).style.color = ‘red’;
- Les formulaires fonctionnement comme des blocks (et non plus avec end_form_tag).
- Ajout des mois et années à la méthode distance_of_time_in_words.
- En cas d’erreur le fichier 500.html est rendu par défaut.
- Il est possible d’exclure certaine extensions du rendu avec layout.
- RESTful tient compte automatiquement de la valeur de params[:format] si il est spécifié.
- Il est possible d’enregistrer de nouveaux MIME types pour une extension.
- Ajout du filtrage de certains paramètres et attributs dans les logs avec filter_parameter_logging (password par exemple, ).
- Le système de routage a été réécrit.
- Dépréciation de certains méthodes, il faut maintenant utiliser les méthodes et non pas les variable de classe tel que @session ou @request.
ActiveSupport
- Il est possible de faire en sorte qu’une constante soit réinitialisé après chaque requête avec Module#unloadable.
- Avec Module#alias_attribute il est possible de créer des alias pour les attributs.
- Enumerable#sum calcule une somme depuis un Array.
- Array#to_s(:db) produit une liste séparé par des virgules.
- Il est maintenant possible d’utiliser Module#alias_method_chain au lieu de deux fois Module#alias_method.
- Division dûn Array avec split.
- Création d’un Hash avec from_xml.
Globalize Rails Core team
Nous utilisons Ruby On Rails depuis maintenant quelques temps le cadre de mon entrepise pour de développement de Pulp. Nous avons très vite eu besoin de contenu multilingue et avons donc choisi d’utiliser l’extension Globalize que nos besoins nous on poussé à quelques peut modifier et améliorer. Changements que nous avons naturellement publiés.
Il y a quelques semaines un utilisateur nous a contacté (mon associé olivier et moi-même) afin de nous demander si nous serions intéraissé par rejoindre l’équipe de developpement de Globalize, il n’en fait lui-même pas parti et n’estime pas avoir les connaissances qu’il faut pour le faire, mais puisque Josh (créateur de l’extension) à demandé de l’aide il s’est permi de nous contacter.
Et il à bien fait. Nous n’y avions pas vraiment penssé, mais maintenant que quelqu’un nous en parlais il nous a semblé intéraissant d’intégrer nos modifications et d’aider à sa mise à niveau d’une extension qui était primordiale pour nous. La dernière version de rails à en effet apporté beaucoup de nouveautés avec lesquels le multi-linguisme ne fonctionne pas. Nous avons donc contacté Josh et l’affaire s’est très vite conclue. Aujourd’hui nous avons mis en place un nouvelle hébergement (par nos soins) pour les sources et un Trac (http://trac.globalize-rails.org), un nouveau wiki hébergé chez stikipad est en phase de remplissage et devrait remplacer l’ancien d’ici quelques jours. Nous également avons mis en place des tests continues et enfin fait passer les tests au complet.
L’équipe de développement de Globalize se compose aujourd’hui de quarte personne : Josh Harvey, Jeremy Voorhis, Olivier Amblet et Yann Lugrin. Nous allons travailler à l’intégration des nouvelles fonctionnalités de Rails et de nos modifications ainsi que naturellement à la correction des problèmes existant.
Rails, version 1.1.2
Les versions 1.1.1 et 1.1.2 de Rails sont sorties rapidement afin de corriger quelques bug et améliorer la compatibilité des applications tournant sur 1.1.0.
La version 1.2.0 est lancé dans le trunk de subversion, une branche stable a été créé afin de pouvoir corriger d’éventuelle problèmes sur la version actuelle mais plus aucune nouvelle fonctionnalité ne sera ajouté.
Variable aléatoire et répartition selon la loi normale
Dans le cadre du développement d’une simulation j’ai été confronté au problème des variables aléatoires. Ruby nous offre une fonction rand avec une répartition uniforme des résultats, c’est à dire que chaque valeur dans la plage de résultat conciédré comme valide (float entre 0 et 1 par défaut) à autant de chance que toutes les autres d’être renvoyé par la méthode.
Dans mon cas précis j’ai eu besoin d’orienter le résultat pour avoir une répartion selon la loi normale qui permet de faire un tirage qui tend plus ou moins vers une valeur moyenne définie. Ruby n’offre pas directement une méthode de ce type mais il existe des formules mathématique permetant de dériver d’un tirage aléatoire uniformément réparti une variable aléatoire répondant à cette loi.
(s * Math.sqrt(-2.0 * Math.log(rand)) * Math.cos(2.0 * Math::PI * rand)) + m
Cette formule utilise deux variables aléatoires et deux paramètres (‘m’ et ’s’) et calcul sur cette base une nouvelle valeur. ‘m’ est la valeure médiane du tirage selon la loi normale, les résultats tendent vers cette valeur qui est également la moyenne des tirages et la valeur qui reviens donc le plus souvent. ’s’ permet de modifier la répartition, plus cette valeur est proche de 0, plus les résulats tendent vers la valeur médiane, au contraire si on augmente cette valeur les résultats vont s’étendre (pour une valeur très élevée, on tend vers une répartition uniforme autour de la valeur médiane).
def random_normal(m, s, man = nil, max = nil)
m = m.to_f
s = s.to_f
min = min.to_f unless min.nil?
max = max.to_f unless max.nil?
value = (s * Math.sqrt(-2.0 * Math.log(rand)) * Math.cos(2.0 * Math::PI * rand)) + m
if (!max.nil? and value > max) or (!min.nil? and value < min)
return random_normal(m, s, min, max)
else
return value
end
end
La méthode random_normal reçois en paramètre ‘m’ et ’s’ dont j’ai parlé ci-dessus. Elle peut également utiliser deux paramêtres facultatifs, ‘min’ et ‘max’ qui définissent des bornes à la plage de résultat. Si un tirage est hors de cette plage il est effectué à nouveau jusqu’à avoir une valeur valide. Il est possible de définir qu’une des deux bornes, les deux ou aucune.
Il est toujours intéraissant de pouvoir tester une méthode comme celle-ci et avoir une représentation visuel des résultats pour ce faire une idée de ceux-ci. J’ai donc collecter les résultats d’un million d’appel à la méthode afin d’en tirer un certain nombre de statistiques (valeur maximum et minimum, valeur moyen, temps d’exécution) et une représentation graphique de la courbe de répartition des résultats.
m = 0.0
s = 10000000000.0
min = -100
max = 100
nb_tests = 1000000
tic_length = 60
start_time = Time.now
random_time = 0.0
test_values = Hash.new(0)
test_values['min'] = m + 1000000000
test_values['max'] = m – 1000000000
total = 0
nb_tests.times do |i|
random_start_time = Time.now
value = random_normal(m, s, min, max)
random_end_time = Time.now
random_time += random_end_time – random_start_time
test_values[value.round] += 1
test_values['median'] = value.round if test_values[value.round] > test_values[test_values['median']]
test_values['max'] = value.round if value.round > test_values['max']
test_values['min'] = value.round if value.round < test_values['min']
total += value
end
end_time = Time.now
puts « Représentation graphique des tests d’une méthode de tirage aléatoire respectant la loi normale »
puts « »
tic = test_values[test_values['medium']].round / tic_length
ok = false
(test_values['min']..test_values['max']).each do |i|
max_length_value = test_values['min'].abs.to_s.length > test_values['max'].abs.to_s.length ? test_values['min'].abs.to_s.length : test_values['max'].abs.to_s.length
string_result = i < 0 ? ‘-’ : ‘ ‘
string_result += ’0′ * (max_length_value – i.abs.to_s.length)
string_result += « #{i.abs} : #{‘.’*(test_values[i]/tic)} [#{test_values[i]}] »
puts string_result
end
puts « »
puts « Nombre de tests : #{nb_tests} (#{end_time – start_time} s) »
puts « Médian : #{m} »
puts « Valeur minimum : #{test_values['min']} »
puts « Valeur médiane : #{test_values['median']} (moyenne : #{total / nb_tests}) »
puts « Valeur maximum : #{test_values['max']} »
puts « Temps moyen par appel à la fonction : #{random_time / nb_tests} »
‘m’, ’s’, ‘min’ et ‘max’ sont les paramètres de la méthode. ‘nb_tests’ est tout simplement le nombre de variable aléatoire qu’on veut récolter, ‘tic_length’ permet de configurer la largeur le la courbe à son point le plus haut, c’est à dire la valeur médiane.
Le fichier complet avec cette méthode, les testes et des commentaires est disponible en pièce jointe.
Rails 1.1, quoi de neuf ?
Le 26 mars 2006, il y a maintenant quelques jours, la version 1.1 de Ruby On Rails est sortie en version stable après avoir passé quelques jours par le stade de Release Candidate.
Pas de précipitation
Cette nouvelle mouture apporte un grand nombre de nouveauté et un certain nombre d’applications et plugins ne fonctionne plus avec. Il est donc fortement conseillé de faire un freeze de rails pour les application en production avant de faire une mise à jour. Pour ceci il existe plusieurs méthodes :
rake rails:freeze:gems
Exporte la version courente de rails dans vendor, attention si vous avez déjà mis à jour rails sur la machine cette méthode ne fonctionnera pas.
rake freeze_edge REVISION=3303
Exporte la version 1.0 depuis le svn de rails, cette méthode permet d’être certain d’avoir la bonne révision.
Les deux méthodes ci-dessus sont idéal pour figer une application en production tout en travaillant avec une autre version de rails sur une machine de développement. Mais il est également possible de faire ceci directement dans svn via la propriété svn:externals pour que les checkouts de l’application soit automatiquement accompagné de celui de la version 1.0 de rails.
Editer la propriété svn:externals du répertoire vendor et y ajouter la ligne suivante comme suis :
svn propedit svn:externals vendor
rails http://dev.rubyonrails.org/svn/rails/tags/rel_1-0-0
Au prochain update rails sera mis à jour dans vendor.
A noté que cette méthode est très utile si on veut travailler avec une version particulière du trunk pour bénéficier de nouveautés mais qu’il faut être prudent puisque des problèmes peuvent survenir.
Ruby 1.8.4
Il est fortement conseillé de passer à ruby 1.8.4 lors de cette mise à jour mais RMagick apporte quelques problèmes. La RC1 de l’installateur pour windows est disponible et une version béta compilé de RMagick pour la 1.8.4 également. Si vous utilisez RMagick et que des tabulations se trouvent dans vos fichiers rhtml il faut les remplacer par des espaces ou attendre que le problème soit résolu avant de faire cette mise à jour qui n’est pas indisspenssable (seul console de rails ne peut fonctionner sans celle-ci).
Alors quoi de neuf ?
Et bien beaucoup de choses, pour commencer plus de 500 problèmes de la version précédente ont été résolu. Mais c’est surtout l’arrivé de RJS (template javascript), d’importantes nouvelles fonctionnalités dans ActiveRecord, respond_to permettant une meilleur intégration des différentes méthodes d’accès au controlleur (AJAX, non-_AJAX et API) et enfin l’apparition des testes d’intégrations qui viennent compléter les testes unitaires et fonctionnels.
Railties
- Le format par défaut du schema de la base de donnée est maintenant ruby et non plus sql
- script/process/spinner n’existe plus et est remplacé par l’option
-r/--repeatsur script/process/spawner - L’environnement de test est forcé lorsque les tests sont effectué.
- La page par défaut index.html donne maintenant des informations sur rails via AJAX et Rails::InfoController
- Un fichier public/javascripts/application.js vide est maintenant créé et automatiquement inclue dans les pages par le helper
javascript_include_tag :defaults. On peut y mettre du code javascript spécifique à l’application - script/console à maintenant une méthode
reload!afin de recharger les models, les helper y sont également disponible - Les tâche dans rake ont maintenant un namespace, par exemple
load_fixturesdeviensdb:fixtures:load. Les anciens nom sont toutefois encore utilisable etrake --tasksvous donnera la liste des nouveaux noms. A noté que db:fixtures:load FIXTURES=peoplepermet maintenant de charger exclusivement certaines fixtures dans l’environnement- Il est maintenant possible de ne lancer que les tests pour les changements depuis le dernier commit via
test:uncommitted
ActiveSupport
- Chaque objet à maintenant la méthode with_options qui permet de faire plusieurs oppérations sur le même objet dans un block avec des paramêtres par défaut
- La méthode to_json renvoie une représentation peut renvoyer la représentation sous la forme d’une chaine JSON de chaque objet
- Les objets enumerables ont maintenant une méthode group_by pour grouper les collections sur la base du résultat d’un block
- Le type Array à maintenant la méthode in_groups_of qui permet de faire une itération sur des groupes d’une certaine taille
- Les types Hashes et Array ont maintenant une méthode to_xml
- Ajout de la métode secondes au type _Fixnum pour permettre de faire
5.minutes + 30.seconds - La nouvelle méthode diff du type Hashes permet de connaitre la différence entre deux hash
- Time à une nouvelle méthode beginning_of_quarter
- Le support de la délégation permet de délégué l’appel d’une méthode d’un model à une association
- Object#copy_instance_variables_from(object) copies les variables d’instances d’un objet dans un autre
- Object#extended_by permet de connaitre les modules inclue ou étendue par une instance
- Object#extend_with_included_modules_from(object) étend une instance avec les modules d’une autre instance
ActiveRecord
- has_many :through permet de faire une association à travers une autre (documentation).
- Les Association polymorphique (explications)
- with_scope (explication)
- Nouvelles méthodes de calcul sur les attributs d’un modèle (introduction)
- Chargement en cascade des données se qui permet d’avoir en une seul requête touts les auteurs, leurs messages et les commentaires dans la requête suivante par exemple :
Author.find(:all, :include=> { :posts=> :comments }) - Héritage par find des options spécifiés lors de la déclaration d’une association has_many et has_and_belongs_to_many
- Représentation XML des données avec la méthode to_xml
- validate_uniqueness_of peut maintenant associé plusieurs colonnes
- t => :delete_all remplace xclusively_dependent
- find pour has_many et has_and_belongs_to_many à maintenant les options , *:limit, * et *:select
- Les fixtures peuvent être placé dans des sous-répertoire de test/fixtures
- validates_length_of fonctionne avec UTF-8
Actionpack
- Template RJS, en plus des templates .rhtml (Ruby HTML) il est maintenant possible de créer des .rjs. Il est donc possible d’écrire des templates avec du code ruby pour générer du code javascript (Documentation)
- alert, fait apparaitre une fenêtre de dialogue
- redirect_to, redirection javascript
- call, pour appeler une fonction javascript
- assign, pour assigner une valeur à une variable javascript
- replace, pour remplacer le code html d’un élément
- insert_html, pour inssérer du code html dans un élément
- visual_effect, pour déclancher un effet visuel
- hide, pour cacher un élément
- Il est possible de se référer à un élément
- select, pour séléctionner un élément avec le séléecteur CSS
- drag and drop
- delay, exécution avec un délai
- Exepetion RJS via une fenêtre de dialog
- Méthodes énumérable
- Il est également possible de générer du code javascript à ajouter dans une vue directement depuis un controller
- Possibilité de créer des Helpers RJS pour mettre à jour un block
- Une action dans un controller peut maintenant répondre à plusieurs type de service (html, xml, javascript via la méthode respond_to
- Possibilité de modifier le parsers de paramêtre en fonction du content/type reçus
- De nouveaux helpers pour formulaire (form_for, form_remote_for, et fields_for)
- Tests d’intégrations. Ceux-ci permettent de tester plusieurs controlleurs et actions de façons successive et le fonctionnement complet de l’application depuis le dispatcher jusqu’à la base de donnée. Ils permettent également de tester des accès concurents à l’application via plusieurs session.
- render(:xml => xml) fonctionne comme render(:text => text)
- Ajout de l’option content_type à la méthode render
- Les fichiers contenant les Helpers ne sont plus obligatoire
- Il est possible de spécifier une autre sélection que la valeur de l’objet au helper select grace à l’option selected
- button_to_function fonctionne comme link_to_function
Prototype
- Nouvelle classe de séléction
- De nouvelles méthodes ajouté à String : truncate, gsub, sub, scan et strip
- Ajax assigne ‘text/javascript, text/html, application/xml, text/xml ’ au header HTTP Accept pour informer Rails qu’il préfaire un RJS en retour mais accepte les autres formats.
- Element.replace est une implémetation de outerHTML fonctionnant sur les différents navigateurs
Cette article est basé sur un poste en anglais de Scott Raymond. Il ne reprend pas la totalité des nouveautés qu’il a cité et aucun des exemples de code. Je vous invite à le lire pour plus d’information. Vous pouvez aussi vous intéraisser au poste de Mike Clark, toujours en anglais et qui fait une liste de modifications oublié de cette nouvelle version.
