ruby
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.
[...]Publication de pictrails 0.3.0
Presque 3 mois jours pour jours après la dernière release de Pictrails 0.2.3, voici la release de la version 0.3.0

Cette nouvelle version apporte son lot de fonctionnalités. La plus importante étant l'ajout du support des sous-galerie En effet, désormais, on peux créer des galeries photos dépendant d'une autre galerie. Cette galerie sera donc visible avec la liste des photos de sa galerie parente. Pour que la navigation soit ainsi plus fluide, j'ai ajouté un fil d'ariane ou breadcrumb pour les anglophiles. On sait ainsi désormais dans quel galerie nous nous trouvons et si celle-ci a des parents.

La deuxième fonctionnalité est surtout la refonte compléte du mass_upload. En effet, le mass_upload ne fonctionnait pas trop si on avait énormément de photo a ajouter. Les threads mongrel ou FastCGI s'arrêtait avec un time out et plus aucune solution de continuer la tâche. Pour ce faire, la première requête liste toutes les images à importer et dans quel galerie. Ensuite à chaque nouvelle requête dans la partie d'administration une série de 5 photos est ajoutés. Pour rendre le système plus conviviale, une progress bar a été ajoutée. Celle-ci évolue progressivement si le Javascript est activé sur votre navigateur. Ce système de mass_upload a bien évidement suivit l'évolution de Pictrails en supportant lui aussi les sous-galeries. Ainsi, il liste de façon récursive les répertoires et créé les galeries avec leurs parents associés.

J'espère que cette nouvelle version vous satisfera. Bien-sûr la liste des fonctionnalités a ajouter n'est pas fini pour arriver à la version 1.0. Si vous avez envie de contribuer n'hésitez pas. Pour plus de détails sur cette version, le site de pictrails a été mis à jour
[...]Où compiler ses fichiers C issue de RubyInline
RubyInline est un joli petit gem qui permet de générer du code C a partir de code Ruby. Ce code C est ensuite compilé et réutilisé durant les appels futurs de la méthode.
Par défaut, RubyInline compile tout dans votre dossier $HOME/.inline. Mais comment faire si l'utilisateur n'a pas de HOME par exemple, où tout simplement qu'il souhaite mettre la compilation dans le dossier $RAILS_ROOT/tmp/inline qui pourrait être une place tout à fait raisonnable.
N'ayant pas trouvé l'information dans la documentation de ce gem, j'ai donc chercher un peu dans le code. J'ai ainsi découvert que le dossier de compilation des fichiers C est géré par la variable d'environnement INLINEDIR. Il suffit donc de définir cette variable dans votre fichier d'environnement.rb pour choisir où sera compilé les fichiers générés par RubyInline.
[...]Vivre avec Rails Edge #22
Traduction de la news #22
Aucun changement hallucinant dans Rails cette semaine avant la RailsConf -
Comme Gregg le mentionnait la semaine dernière dans le Rails
Envy podcast, ce sont les jours pré-2.1 (Rails 2.1 sera
probablement sorti au RailsConf), ce qui sera une façon
simple de voir pourquoi. Tous les tests de rails passe désormais sur Ruby 1.9
après un long bug sur #module_eval résolu dans le trunk de Ruby
1.9 (voir ce
thread pour plus de détails).
Je serais (pour la première fois) au RailsConf 2008 à Portland, Oregon, ce jeudi prochain - Si quelqu'un souhaite me voir et me reconnaitre avec ma photo de Facebook, s'il vous plait venez me dire salut.
Le rapport de cette semaine couvre les changement du 19 Mai 2008 au 25 Mai 2008 (le jour correspondant à l'enregistrement du Rails Envy podcast).
Les méthodes first et last fonctionnent désormais avec les associations et named_scope
Vous vous souvenez comment le merge
du gem has_finder à l'intérieur de rails a
permis de faire des choses comme Post.first et
Post.last?
Maintenant vous pouvez allez dans l'étape suivant et utiliser les mêmes méthode dans vos association ActiveRecord. Par exemple:
post = Post.find(1) first_comment = post.comments.first
Si vous avez récement utilisé named_scope, vous pouvez désormais faire ceci:
post.comments.recent.last
Cette belle petite fonctionnalitée a été gentiement apporté par Ryan Bates (oui, le Ryan Bates du fameux Railscasts).
Révision concernant cette fonctionnalités: http://github.com/rails/rails/commit/73c59638549686fccc749ffd3ac53cb533c5fd61
Cache stores a désormais une méthode exist? et ajouté dans le controllers un fragment_exist?
L'enregistreur de cache dans Rails (Memcache, file stores, etc.) peux désormais avoir une méthode exist? qui vérifie si une valeur de cache existe pour la clé de cache. Cela permet aux controllers Rails de disposer d'une méthode fragment_exist? qui permet de vérifier l'existence d'un fragment de cache:
fragment_exist?('example.com/foo/bar')
Cette petite amélioration a été gentiement apporté par José Valim.
Révision concernant cette fonctionnalités: http://github.com/rails/rails/commit/99860b72aebe0348f41e82d4710343498d89a84b#diff-2
Créer un enregistrement d'une association avec un block en argument
Vous pouvez désormez créer des enregistrement pour les associations comment ceci:
post.coments.create!(:title => 'Techcrunch') do |c| c.body = "Rails can't scale" end
Ceci est ajouté au changement de ActiveRecord::Base.create indiqué précédement.
Ce patch a été réalisé par (encore une fois) Ryan Bates.
Révision concernant cette fonctionnalités: http://github.com/rails/rails/commit/6cba97d2a449faf21aec9fe9d4434067e414226f
Comme toujours, vous pouvez laissez toutes suggestions pour améliorer cette série de Vivre avec Rails.
[...]