ruby
Migration sur Typo-5.1.3 et mise à jours du script capistrano
Voilà, aussitôt sortie aussitôt installée. Alors que Typo-5.1.3 est sortie dimanche, j'ai mis à jour ce blog. Comment faire une migration si rapide ? Simple un bon script Capistrano :
require 'mongrel_cluster/recipes' set :application, "typo" set :repository, "http://svn.typosphere.org/typo/trunk" set :domain, "shingara.fr" # If you aren't deploying to /u/apps/#{application} on the target # servers (which is the default), you can specify the actual location # via the :deploy_to variable: set :deploy_to, "/var/rails/blog-typo" # If you aren't using Subversion to manage your source code, specify # your SCM below: set :scm, :subversion set :runner, "rails" set :user, "rails" set :use_sudo, false set :mongrel_conf, "#{current_path}/config/mongrel_cluster.yml" role :app, domain role :web, domain role :db, domain, :primary => true task :update_config, :roles => [:app] do run "cp -Rf #{shared_path}/config/* #{release_path}/config/" run "ln -s #{shared_path}/files #{release_path}/public/files" end after "deploy:update_code", :update_config
Il ne suffit plus que d'avoir dans le dossier /shared/ le dossier /config/ comprenant les fichiers de configurations : database.yml et mongrel_cluster.yml. Après à chaque mises à jours de typo : cap deploy:migrations. Tout sera fait pour toi.
C'est pas beau la vie en Ruby ?
[...]Le rubyFlow FR disponible
Après que Peter Cooper ait libéré le code original de rubyflow, Bruno Michel a pris les choses en mains pour traduire l'application. L'association RubyFrance a ensuite hébergé le tout. Nous voilà donc maintenant avec notre propre rubyflow FR. Bravo pour cette initiative.
[...]Gettext avec Rails, ca peux être long pour un formulaire en erreur
Aujourd'hui, j'ai passé la journée à essayer de comprendre un problème que j'avais sur l'application que je réalise dans le cadre de mon nouveau travail. Ce bug est très simple. Durant la validation d'un formulaire, si celui-ci n'était pas valide, je retournais sur la même page qui m'indiquait les champs en erreur. Dans la pratique, ceci est très simple. Mais dans notre cas, la page mettait pas moins de 40 secondes à se renderer. Car la latence n'avait pas lieu dans le controlleur, mais bel est bien durant le rendering de la page.
Pour essayer de comprendre la cause de tout ça, j'ai fini par réaliser un profile de ma requête avec le script /script/performance/request qu'il a déjà fallu faire fonctionner, mais ceci fera l'objet d'un autre billet. Une fois le profilling réalisé, j'ai constaté que ce qui me posait problème était une recherche incessante de traduction des messages d'erreurs. Après de longues recherche dans le code, j'ai fini par découvrir la vraie cause du problème.
Dans Rails, durant chaque création de tag, il y a une demande de récupération de errors.on pour connaitre là où les erreurs sont et ainsi mettre en surbrillance le champs ou non. Mais là où normalement dans Rails, ce n'est qu'un appel vers un valeur figée, Gettext a décoré la méthode pour réaliser une traduction de la chaine. Bien sûr si ce n'était que ça, ça pourrait encore passer, car finalement c'est le comportement en production. Les chaines étant misent en cache, l'accès est quasiment aussi rapide que sans gettext. Mais dans le cas d'un environnement en Développement, il n'y a aucun cache des chaines de Gettext. Ainsi à chaque tentative de traduction le mo file est chargé et une itération à lieu sur tout ce fichiers pour trouver la chaine à traduire. C'est ces itérations incessantes qui entrainait un temps de traitement extrêmement long de ma requête.
Ce phénomène n'a lieu uniquement qu'en environnement de développement, car il y a un test sur le nom de l'environnement. Dans tous les autres cas autre que développement, les mo sont mis en cache.
Pour résoudre ce problème, soit vous changez le nom de votre environnement par défaut, par exemple dev au lieu de développement, où alors mettre le code GetText.cached = true dans votre environnement.rb. Cela implique par contre que si vous modifiez les fichiers mo, il faudra redémarrer le serveur pour avoir les nouvelles entrées.
Travailler avec rails fait trouver des bugs
Alors que j'ai commencé à travailler professionnelement parlant avec Rails depuis mon départ de CapGemini et mon arrivée à JTEK. En une semaine et demi, je constate 1 bug sur rails 2.1, un bug sur Edge et un comportement ajouté en Rails 2.1 qui disparaitra en Rails 2.2 (déjà disparu sur Edge)
#has_one demande la validation de sa liaison
Durant la migration de l'application développé au sein de Jtek de Rails
1.2 à 2.1, j'ai constaté que les éléments #has_one sont désormais
validé durant la validation du parent. En effet, ce comportement n'était pas
présent dans les versions antérieurs à Rails 2.1. Par contre, la validation du
#has_many est quand à elle effectuée depuis plusieurs version de
Rails.
Par contre après une lecture du code de Rails edge, actuellement, ce
comportement disparaitra complétement en Rails 2.2. En effet, une option
:validate a été ajouté au méthode #has_many,
#has_and_belongs_to_many et #has_one. J'ai parlé de
ce comportement dans une news
Vivre avec Rails.
Pour palier ce problème, j'ai créé un petit plugin rails qui permet de
couper la validation sur le #has_one. Vous pouvez trouver les
sources sur le github de JTek.
Bug de logger dans le Runner de Rails-2.1
Sur ce point j'ai reporté un bug sur le lighthouse de Rails. En effet, j'ai
constaté que si on utilisait le logger par défaut de Rails, et qu'on réalisait
un log dans le code executé par script/runner il ne se retrouvait pas loggé
dans le fichier production.log en mode production. Par contre en mode
développement, tout se passait bien. En fait, le problème vient du nouveau
Logger par défaut de rails qui est une surcouche au Logger de Ruby. Ainsi, il
contient un buffer qui est flushé régulièrement. Mais en fait en mode
production, le flush est désactivé. On peux ainsi retrouvé différent moment de
flush dans le code de rails pour vider ce buffer. Mais voilà, avec
script/runner, on peux se retrouver à ne pas avoir flusher tout le logger à la
fin de sa tâche. Pour palier le problème, il suffit de faire un
RAILS_DEFAULT_LOGGER.flush à la fin du fichier script/runner.
Sinon vous pouvez essayer de faire bouger le rapport de bug que j'ai
ouvert
Eager Loading empêchant la migration en production
Voulant testé un peu Pictrails avec Edge, pour reporté le bug précédent, je me suis retrouvé bettement à ne pas pouvoir réaliser la migration en mode Production de Pictrails. J'ai ainsi trouvé la cause qui est en fait le eager loading des models durant l'initialisation. Dans mon model Pictures, il se trouve que je fait une demande d'information sur un autre model. Du coup Rails tente de faire une requête SQL avant de réaliser la migration. Forcement, ca peux pas fonctionner. La seule méthode pour éviter ca est de mettre l'option config.classe_cache à false dans le fichier de configuration. J'ai bien sûr reporté un bug à ce sujet. [...]
Sortie de Pictrails 0.4.0
Alors que je commence un nouvelle emploi, voici la nouvelle version de Pictrails. Cette version 0.4.0 sort assez rapidement après la version 0.3.x. Elle apporte effectivement assez peu de nouvelles fonctionnalités, mais elle a l'avantage d'être maintenant compatible avec Rails 2.1 Les prochaines versions de Pictrails seront peut-être un peu moins fréquente. Mais la roadmap se charge de plus en plus et même quelques personnes commencerait à utiliser Pictrails.
Voici la liste des nouveautés de cette version :
- Ajout du support des Tags. Ainsi chaque image peux avoir une série de Tag qui lui ai associé.
- Ajout d'un flux Atom relié au gallerie
- Ajout d'une bar de coté avec la liste des galleries disponible sur l'application. Elle est organisé sous forme d'arbre exactement comme est l'arborescence.
- Ajout d'un nuage de Tag global et gallerie par gallerie dans la bar de coté.
Vivre avec Edge (ou quoi de neuf dans Rails Edge) #3
traduction de Vivre avec Edge #3
Il n'y a pas grand chose à noter comme gros changements ou fonctionnalités dernièrement dans edge Rails, alors je vais parler des commits rails concernant quelques bugs fixes et changements mineurs que je n'ai pas indiqué précédement. Il y a eu un travail en cours avec un refactoring et multithreading de ActionPack ainsi qu'un peu d'activité sur ActiveModel, mais rien de réelement concret encore (c'est toujours en cours de travaux).
Comme d'habitude n'hésitez pas à laisser des critiques ou suggestions dans les commentaires.
Support de Thin avec script/server
script/server vérifie désormais la disponibilité de Thin et l'utilise. Pratique si
vous utilisez Thin comme serveur de production (et voulez lancer avec le même
serveur durant le développement). Vous devez ajouter config.gem
'hin' en premier dans votre environment.rb pour que cela
fonctionne.
Ce patch est une contribution d'un des gars de fluxin.
String#humanize peux être configurable par les régles d'inflection
La méthode d'extension du core String#humanize est utilisé
pour convertir les string avec des underscores en texte lisible plus
facilement (utilisé pour les noms des colonnes). Par exemple,
"actor_salary".humanize => "Actor salary" "anime_id".humanize => "Anime"
Parfois cela ne fonctionne pas aussi bien, quand vous avez des héritages de
tables ou des noms de colonnes "inhumain" comme "act_sal_money" (qui est
réellement "Actor salary", mais qui sera #humaize-d en
"Act Sal Money").
Vous pouvez désormais spécifier une régle d'inflection (exactement comme pour les règles de mots pluriel/singulier/irrégulier/invariable).
Inflector.inflections do |inflect| inflect.human /_cnt$/, '\1_count' inflect.human 'act_sal_money', 'Actor Salary' end
Remarquez que vous pouvez aussi utiliser une expression régulière pour convertir une colonne comme "click_cnt" en "Click count".
Merci à Dan Manges et Pascal Ehlert pour ce patch.
Possibilité de spécifier des conditions sur des tables multiples en utilisant un hash.
Pratik a commité un petit (mais très pratique) changement d'ActiveRecord qui permet de spécifier des conditions sur les jointure dans leur propre hash. Un exemple sera plus explicite:
Anime.all( :joins => :character, :conditions => { :active => true, :characters => { :gender => 'female' } } )
La requête ActiveRecord précédent permet de trouver tous les anime "actif" qui comme charactère une "femme".
Outro
C'est tout pour cette semaine dans "Living on the Edge". Faites moi savoir si vous désirez voir plus d'information sur les changement et bug fixes mineurs que j'ai mis à l'écart cette semaine.
[...]Vivre avec Edge (ou quoi de neuf dans Rails Edge) #2 -amélioration des performances
traduction de Vivre avec Edge #2
La première news Vivre avec edge a parlé des changement de l'API depuis Rails 2.1, et durant cette news, les améliorations de performances seront indiqué comme promis.
En avant...
Les templates Erb plus rapide
Jeremy Kemper a rendu le processus d'Erb plus efficace, spécialement les méthodes d'helper concat et capture.
Le "spécial" Erb _erbout a été remplacé par une variable d'instance qui permet ceci:
- Meilleur performance (mémoire) parce que bindings ne pas pas longtemps autour
- Moins de d'évaluation qui est généralement couteux.
- Il n'y a pas besoin de séparer la variable
_erboutquand vous remplacer un nouveau buffer (de string) - Le buffer est généralement disponible via une méthode
output_bufferécriture et lecture (alors vous pouvez les overrider si vous le souhaitez)
Changesets en relation: 933697a - 0bdb7d3 - 4d4c8e2
Les helpers JavaScript et les partials sont plus rapide.
L'initialisation des templates partial et des helpers Javascript ont été refactoré et optimisé pour une meilleure vite et efficacité grâce à Jeremy Kemper. Quelque optimisations de Jérémy ont été commité récement. Vérfiiez avec les commits de Rails (comme pour tout projet Open Source de qualité) - Vous apprendrez plein de chose.
Changesets en relation: partials – JavaScript helpers
Accélération de la méthode RecordIdentifier
Le RecordIdentifier est plus rapide avec la simple utilisation de memo-ization, réduisant ainsi l'utilisation des Inflections entre autre. Le RecordIdentifier est largement utilisé dans le cache des clé, des chemins des templates de partial, et dans la plus part des endroit où vous identifiez un model ActiveRecord sans le savoir avec ton id actuel.
Changesets en relation par Jeremy Kemper: c1a9820 – 566d717
[...]Afficher les Log SQL avec Merb et DataMapper
Depuis peu, je tente d'utiliser Merb et DataMapper. Une différence notable entre Merb et Rails est le système de log. Comme Merb est ORM Agnostique, il n'affiche pas de base les logs SQL. J'ai cherché plusieurs fois comment avoir mes logs SQL de DataMapper directement dans ma console. J'ai fini par la trouvé sur le wiki de DataMapper. Je vous livre donc l'astuce :
Merb::BootLoader.after_app_loads do DataObjects::SQlite3.logger = DataObjects::Logger.new(STDOUT, :debug) end
Vous pouvez bien-sûr modifier le SQlite3 par Postgres ou MySQL. Cette comment fait une sortie en mode debug sur STDOUT. On aurait aussi pu mettre un fichier ('log/dm.log').
Pour connaitre la liste des niveaux de logs, la voici :
- fatal
- error
- warn
- info
- debug
Vivre avec Edge (ou quoi de neuf dans Rails Edge) #1 - changement d'API et des tests de performances
Voici la nouvelle traduction de Vivre avec Edge. Par contre, cette fois ci, comme annoncé dans cette news, cette news est issu du blog officiel de rubyonrails et non plus du blog de Chu Yeow
Comme Gregg Pollack l'indique il y a une semaine, Je conserve une note hebdomadaire au sujet des changements de edge Rails. C'est la première fois que Living on the Edge(of Rails) est apparu officiellement sur le blog officiel de Ruby on Rails.
Living on the Edge est une note hebdomadaire que je mettais sur mon propre blog après plusieurs récupération par Gregg Pollack of Rails Envy depuis décembre 2007. J'avais l'habitude d'être une contributeur actif de rails et non pas trop une personne qui réfléchis. Gregg et Jason ont été génial de m'ajouter à leur podcast hebdomadaire.
Et maintenant je suis ici, alors je vais essayer de faire de mon mieux et n'hésitez pas à être très critique pour que ça soit utile pour vous. Quand je blogguais cela dans mon petit blog personnel, ce n'était pas vital d'avoir une audience large et significative (NdT: Au moins sur ce blog ça reste toujours le cas). Laissez vos suggestions et critique dans les commentaires. Ils seront grandement appréciés.
De toutes façon il y a eu énormément de nouveauté durant les deux semaines après la release de Rails 2.1, changement de l'API et amélioration des performances. Donc au lieu de faire une très gros post, j'ai décidé de le séparé en 2 posts pour les nouveautés et changement d'API et les améliorations de performances. Dans ce post, je parlerais des nouveautés et changement de l'API
Changements mineurs de l'API
Commençons avec les changements mineurs de l'API.
link_to peux désormais prendre un block
Le helper link_to peux désormais prendre en argument un block. Utile dans les cas où vous avez long texte d'hyperlien avec des variables.:
<% link_to(@profile) do %> <strong><%= @profile.name %></strong> - <span>Status: <%= @profile.status %></span> <% end %>
Certaine personne trouve cela plus propre que:
<%= link_to "<strong>#{@profile.name}</strong> -- <span>Status: #{@profile.status}</span>", @profile %>
Ce changement a été apporté par Sam Stephenson (du fameux Prototype) et DHH.
ActiveRecord::Base#merge_conditions fait maintenant partie de l'API public
Jeremy Kemper a rendu public la méthode ActiveRecord::Base#merge_conditions.
C'est vraiment très pratique si vous avez des conditions issues de multiples sources ou qui se combine pour différentes raisons.
Post.merge_conditions( {:title => 'Lucky ☆ Star'}, ['rating IN (?)', 1..5] ) => "(`posts`.`title` = 'Lucky ☆ Star') AND (rating IN (1,2,3,4,5))"
Notez bien que cela merge uniquement avec un boolean SQL AND (pas ORs).
Les associations peuvent prendre une option :validate
les associations peuvent désormais accepter une option c
class Anime < ActiveRecord::Base has_many :characters, :validate => true end
Cela indique à ActiveRecord de valider l'association characters quand vous enregistrer le model Anime - exactement comment fonctionnait :validates_associated. La valeur par défaut est false, qui est le comportement actuel dans Rails 2.1 et plus récent, donc pas d'agitation à avoir. Cela fonctionne pour toutes les autre associations comme (has_one, belongs_to, has_and_belongs_to_many).
Merci à Jan De Poorter et Pratik Naik pour cela, qui permette aussi de résoudre un mauvais bug.
ActiveSupport::StringInquirer et avantage de la méthode Rails.env.development?
David Heinemeier Hansson (généralement abbrégé par DHH – désolé!) a récemment ajouté un sous-classe à String, ActiveSupport::StringInquirer qui permet de faire ceci:
s = ActiveSupport::StringInquirer.new('awesome') => "awesome" s.awesome? => true s.sucks? =>; false
Une utilisation immédiate de cette classe est quand vous voulez vérifier l'environnement de votre application en fonctionnement : Rails.env est enrobé en StringInquirer alors vous pouvez utiliser des méthodes comme Rails.env.development? et Rails.env.production?.
Core extensions: Object#present? et Enumerable#many?
DHH a aussi ajouté une extensions au core. C'est quelque peu trivial, mais peu rendre le code plus lisible. Le première est Object#present?, qui est essentiellement !Object#blank?
[].present? => false [1, 2].present? => true "".present? => false "i'm here".present? => true
Une extension Enumerable#many? a aussi été ajouté qui réalise simplement un test conditionnel sur enumerable.size > 1:
[].many? => false [:just_me].many? => false [:just_me, 'my_friend'].many? => true
Object#present? changeset – Enumerable#many? changeset
Syntaxe de block déclaratif pour l'écriture de tests
DHH s'est inspiré de Jay Fields quand il commita cette nouvelle syntaxe. Vous pouvez maintenant écrire vos tests (Test::Unit) avec un style de block déclaratif comme :
test "an anime should be invalid if any of its characters are invalid" do # Your usual test code here. end
J'utilise rarement Test::Unit (sauf pour soumettre des patchs à Rails) et préfère RSpec – Ce style déclaratif pour écrire des tests est vraiment plus lisible.
Tous les tests générés par Rails utilisent désormais cette syntaxe.
Performance tests
Jeremy Kemper a fait un travail en profondeur pour optimiser et améliorer les performances de Rails, alors c'est sans surprise que cela a été introduit comme nouveau type de test d'intégration. Les tests de performances.
Vous pouvez utiliser le générateur de test de performance (ajouté par Pratik dans 23232a) pour générer des tests de performances.
script/generate performance_test LoginStories
Le lancement du test de performance nécessite ruby-prof >= 0.6.1, qui n'est pas encore sortie. Mais vous pouvez récupérer sa version en développement à partir des sources et en installant vous même le gem (Je vous conseille de récupérer le ruby-prof que Jeremy a forké). Il est intéressant de remarquer qu'avec la sortie de ruby-prof 0.6.1, ruby-prof supportera le profiling des tests écrits avec Test::Unit
Attention - Si vous faites un petit code de test (requêtes sur plusieurs actions, quelque soit le cas d'utilisateur que vous voulez testez en performance) et lancez le test. Vous aurez la sortie suivante (si vous avez dirigé la sortie habituel de ruby-prof vers le répertoire test/tmp/performance de votre application Rails):
> ruby performance/login_stories_test.rb Loaded suite performance/login_stories_test Started LoginStoriesTest#test_homepage (32 ms warmup) process_time: 11 ms memory: unsupported objects: unsupported . Finished in 0.870842 seconds.
Les résultats memory et objects ne sont pas supporté, parce que je n'avais pas patché mon interpréteur Ruby au support du proflling de mémoire. Vous aurez besoin de patcher certain interpréteur ruby pour activer le profiling de la mémoire et de GC. Je souhaiterais vous en dire plus à ce sujet, mais je suis en terrain inconnu. Il y a plus de détail ici (en) sur la méthode à suivre pour patcher Ruby pour le profilling de la mémoire. Je laisse les personnes plus qualifiée sur ce sujet expliquer tout ça.
Outro
C'est tout pour le moment concernant les nouvelles fonctionnalités et changement dans Rails depuis Rails 2.1 - Les améliorations de performances arriveront dans un prochain post et j'ai laissé aussi intentionnellement de coté le support de Rack qui n'est que partiellement mergé dans Edge.
Si il y a des erreurs ou que vous avez des suggestions sur comment faire un meilleur post, s'il vous plait indiquez le en commentaire. Toute information sur le patch de l'interpréteur Ruby pour supporter le profiling de la mémoire et aussi le bienvenue. Si j'ai laissé de coté des éléments qui ne vous semblez pas le nécessiter, laisser moi un commentaire.
[...]Le piege des routes à éviter
Alors, que je testais Pictrails pour la release en version 0.3, j'ai par hasard créé une galerie s'appelant "new". Ayant implémenté un système de PrettyURL pour pictrails, j'ai changé les routes REST pour non pas afficher l'id de la galerie dans l'url mais son nom. Ainsi, comme ma galerie s'appele "new", je devais allez sur l'URL : /galleries/new.
Mais voilà comme galerie était une ressource REST, la route /galleries/new est déjà réservé et je me suis donc retrouvé sur l'url de création d'une Gallerie et non sur l'url de visualisation de la galerie new. C'est ainsi que je suis tombé dans le piège des routes à éviter.
Maintenant, que j'ai trouvé le bug il a fallu trouvé la solution et plus que de trouver la solution, il fallait trouver une solution propre. En effet, basiquement, on peux créer un validateur qui vérifie que le nom n'est pas "new", mais cette technique ne me semblait pas idéal surtout pour l'avenir et le maintient à terme de cette solution. J'ai donc commencé à en discuter avec les personnes présentent sur le chan #rubyonrails.fr. C'est ainsi que webs m'a proposé une solution tout à fait élégante en me donnant un code de sunny. La vérification directe de l'existence ou non de la route. Voici le bout de code qui permet cette vérification :
permalinks = ActionController::Routing::Routes.routes.collect {|r| r.generation_structure.match(/"\/galleries\/([\w]+)/)[1] rescue nil }.uniq.compact
On récupère ainsi tous les mots utilisés dans nos routes et commençant par galleries. Sur Pictrails, nous obtenons ainsi "pages" et "new". Il suffit ensuite d'empêcher la création de galerie avec ces noms.
[...]