Rulu 2011 : la communauté Ruby (on Rails) Européenne vaut vraiment le détour


Un p'tit peu de retard dans la restranscription de RULU, la conf' Ruby (on Rails) Lyonnaise qui a eu lieu le Week-end du 25/26 Juin, mais je tenais à laisser une trace quelque part de cet évenement. Oui, évenement, on peut le dire.

Tout d'abord : la qualité des intervenants

Sven Fuchs (I18n de Rails) Hampton Catlin (Monsieur SASS, HAML), Nick Sutterer (Apotomo, Cells)... j'en passe, et des meilleurs, comme le dit l'expression. J'étais franchement impressionné par le niveau des speakers, surtout pour une première.

Ensuite : la qualité et la diversité des Talks

J'avoue qu'au début, j'avais un peu peur d'être laché par des talks trop orientés technique et "high level". Il n'en fut rien, chaque intervenant prenant soin de rendre son talk réellement vivant, accessible, d'une part. Certains talks étant carrément dans le registre "social", d'autre part (Joshua Wehner par exemple, sur le thème de la nécessaire diversité, pour l'instant absente du milieu Geek).
En bref, je n'ai absolument pas été perdu par d'éventuelles envolées lyriques de techniciens autistes. Bien au contraire même, y compris quand certains thèmes étaient bien épais (le Http Streaming, notamment), j'ai trouvé les intervenants remarquables part leur sens de la pédagogie et de l'écoute.

Ne pas oublier : l'organisation

Un grand bravo à tout le Staff, qui a fait un travail de Titan en très (très !) peu de temps. La participation de l'INSA fut aussi à noter (les locaux étaient juste parfaits). Franck, Damien, Vincent, Camille, Jean Michel (voui, j'en oublie, ne m'en voulez pas)... Vraiment, du bon boulot.

Finalement : la communauté Ruby Européeenne

Un aspect particulièrement intéressant dans ce genre d'évenement à taille humaine (environ 100 personnes), ce sont les échanges ; et de ce côté là c'était aussi, vraiment, un bon moment ! Toulouse, Nantes, Paris, Nice... mais aussi Allemagne, Pays Bas, Suisse ou Angleterre... en ce qui me concerne, j'ai toujours beaucoup de plaisir à m'ouvrir à d'autres points de vue, sortir de mon trop petit monde habituel.
Un dernier petit point que j'ai aussi beaucoup aimé, conséquence directe du milieu dans lequel Rails est le plus utilisé : la communauté regroupe un grand nombre de gens ayant lancé leur business. Beaucoup de "Start-uper" donc, et de nombreux échanges sur comment monter sa boite dans le Net.

Enfin, et je concluerais sur ce point qui ne cesse de m'épater : la communauté Ruby(on Rails) est vraiment une communauté de gens ouverts, intelligents et agréables. Techniquement exigeants, qui ont tous des Macs et ne parlent qu'Anglais, certes, mais des gens qui valent le coup d'être connu. Des gens qui ne se la racontent absolument pas et sont toujours prêt à vous donner un petit coup de main.

Si ça vous tente, et même si vous n'êtes pas (encore) dans la techno pour le moment, passez donc boire une bière (ou deux) au prochain apéro Ruby à Lyon : ce mardi 12 juillet à l'Antre Autre, lyon 1er !



Commentaires Aucun commentaire pour le moment

Redimensionnez vos images à la volée avec Ruby on Rails


J'ai re-factorisé et modifié en profondeur la syntaxe d'appel de mon bon vieux plugin Thumbnailer. Certes, vous pouvez déja redimensionner les images lors de l'Upload avec paperclip, mais thumbnailer vous permet d'aller encore plus loin :

  • Resize à la volé au niveau de la vue
  • Calcul automatique des proportions
  • Gestion automatique du cache, les images ne sont traitées qu'une seule fois par RMagick
  • Possibilité d'appel en "remote", redimensionnez vos images depuis votre client en JS !

Niveau utilisation, on ne peut pas faire plus simple :

# View
<%= thumbnailer :src=>'/images/my_image.jpg', :width=>'200' %>
Et le plugin se charge tout seul de vous générer une image de 200 pixels de large, qui est mise en cache dans '/cache/images/200xauto/my_image.jpg'. La vue finale affichant un tag img comme celui-ci :
<img src='/cache/images/200xauto/my_image.jpg?1305495323' width='200' alt='my_image' />

Tous les attributs possibles d'une balise img sont reconnus, y compris les évenements JavaScript. L'attribut 'alt', si il n'est pas spécifié, sera automatiquement généré à partir du nom de fichier. Vous noterez aussi que le nom de fichier est suffixé par un timestamp, permettant au cache client side de gérer une image différente mais portant le même nom de fichier, tout comme le 'image_tag' original de Rails.

En bonus, avec le paramètre "remote", l'appel de l'image peut aussi se faire directement depuis le paramètre 'src' du tag img :

# View
<%= thumbnailer :src=>'/images/my_image.jpg', :width=>'200', :remote=>true %>

# Final output
<img src='/thumbnailer/200xauto/images/my_image.jpg' width='200' alt='my_image' />

Effet de bord sympathique, vous disposez maintenant d'une simple URL pour appeler une image de n'importe quelle dimension depuis votre client en Javascript, genre :

$('my_image').src='http://my_domain.com/thumbnailer/200xauto/images/my_image.jpg';
alert("Look ! The image has been resized !");

Ca fait maintenant 2 ans que j'utilise ces features dans tous mes projets. Au début c'était une collection de helpers, de routes et de controllers, puis j'ai pris un peu de temps pour packager tout ça dans un plugin. Je pense maintenant que cette nouvelle version est plus clean et efficace, mais je vous laisse vous faire votre avis là dessus. Comme d'habitude, si vous avez des remarques, laissez un commentaire...



Commentaires Aucun commentaire pour le moment

Vous faites quoi le 25/26 Juin ?


Le Week-end du 25/26 Juin se déroulera Ruby Lugdunum, la conf. Lyonnaise autour de Ruby on Rails ! Au programme sont d'ors et déja confirmé Sven Fuchs (Rails Core contributor) et Konstantin Haase (l'un des principaux Developpeur de Sinatra). Il y aura aussi d'autres conf autour de Rubynius, "Solid" application concepts...

L'évenement devrait logiquement se faire sur le Campus de la Doua, et l'ambiance promet d'être -comme toujours avec la communauté Ruby- sérieuse mais sans prise de tête (si si, c'est possible).

Tous les détails sont sur Rulu.eu, et pour rester au courant des préparatifs, le mieux est de s'abonner au compte Twitter.



Commentaires Aucun commentaire pour le moment

SIPS/ATOS et Ruby on Rails avec le plugin 'atos'


Après Paybox, je me suis dernièrement interessé à SIPS/ATOS, poids lourd du paiement ligne hexagonal. Derrière une apparente complexité, le principe est en fait assez simple :

  • L'acheteur valide son panier, un controller récupère les paramètres (prix, id du panier...), les envoie dans un binaire qui crypte le tout et renvoie un formulaire HTML avec 3 (ou +) logos de carte de crédit au sein du site marchand
  • L'acheteur choisi la carte de crédit appropriée et part sur le site de la banque
  • Une fois les numéros de carte validés sur le site de la banque, celui-ci répond au marchand "dans le dos du navigateur" (c'est l'auto-response) via une chaine cryptée
  • un controller récupère l'auto response et la passe à nouveau dans un binaire afin d'en obtenir un tableau associatif

Ne trouvant rien de simple qui me convienne, j'ai codé un petit plugin qui permet de faire tout ça dans Rails très facilement. Dans une console à la racine de votre appli :

script/plugin install git@github.com:gbarillot/atos.git

Ensuite, déposez les fichiers fournis par la banque dans /lib/atos. Le répertoire lib doit ressembler à ça :

/mon_appli
  /lib
    /atos
      /bin
        request
        request_2.4.18_2.96
        ....
      /param
        certif.fr.014295303911111
        parmcom.014295303911111
        parmcom.sherlocks
        pathfile

Petites remarques : le numéro "014295303911111" en suffixe correspond au marchant_id de test, et "sherlocks" correspond au fait que je passe par LCL. Si vous passez par la Société Générale, vous aurez "parmcom.sogenactif". Je préfère vraiment le "conventions over configuration", mais vous pouvez aussi passer les chemins vers vos fichiers au niveau de l'instanciation de la classe Atos. Ca rajoute juste une étape :

atos = Atos.new(
  :root_dir=>'/path/to/your/main/dir'
)
.... et ensuite :
@request = atos.request(
  :merchant_id=>'014295303911111',
  :amount=>'1500', 
  :customer_id=>session[:customer_id],
  :automatic_response_url=>"http://mon_site.com/payment/validate",
  :normal_return_url=>"http://mon_site.com/payment/fr/confirm",
  :cancel_return_url=>"http://mon_site.com"
)

Tant que nous sommes dans le paramétrage des fichiers, déposez aussi le répertoire "logos" et contenant les logos des cartes dans un répertoire public de votre appli (par exemple /public/images/logos). Prenez aussi soin de renseigner le fichier "/lib/atos/param/pathfile" avec tous les chemins __en absolu__ vers les différents répertoires que nous venons de créer

Ok, maintenant que tout est en place, on va pouvoir commencer à faire tourner tout ça. Récuperez l'action de l'acheteur lorsqu'il valide son panier via l'URL de votre choix, et générons la requête. Depuis le controller :

@request = Atos.new.request(
  :merchant_id=>'014295303911111',
  :amount=>'1500', 
  :customer_id=>session[:customer_id],
  :automatic_response_url=>"http://mon_site.com/payment/validate",
  :normal_return_url=>"http://mon_site.com/payment/fr/confirm",
  :cancel_return_url=>"http://mon_site.com"
)

render :template=>'payment/call_request'

Si tout se passe bien, nous récupérons dans @request un formulaire HTML avec les logos des cartes, ainsi qu'une variable "DATA" dans un champ "hidden" contenant l'intégralité de notre requête cryptée, il n'y a plus qu'à l'afficher dans le template (ici avec HAML) :

%span
  = "Sélectionnez votre type de carte :"
%br
= @request

------------ L'acheteur clic sur un des logos de carte et se rend sur le site de la banque. Celle-ci va maintenant nous répondre ---------------------

On récupère l'auto-response sur une URL à l'écoute en POST (je vous laisse créer la route de votre choix, dans mon exemple, c'est /payement/fr/validate). Il n'y a que 2 lignes à ajouter dans le controller approprié :

      
response = Atos.new.response(datas)

response[:response_code] # 00 => transaction réussie
...

Et hop, on obtiens un joli Hash avec toutes les variables de réponse disponibles dans l'API (voir le "dictionnaire des données" fourni avec l'API pour tous les détails). Maintenant, à vous de traiter cette réponse selon que le paiement a été accepté ou refusé, puis de valider l'achat dans la Base...


Quelques petits détails :

  • les 6 paramètres que j'utilise dans mon exemple au niveau de la requête sont les seuls à être requis par le plugin, mais vous pouvez tout à fait envoyer tous les paramètres stipulés dans le "dictionnaire des données", rajoutez simplement les couples "clef/valeur" dans le hash de la requête.
  • Par défaut la langue et la devise utilisés sont "fr/euro", mais vous pouvez surcharger avec ceux de votre choix au moment de l'instanciation de la classe Atos.
  • Les URL de retour (normal/cancel) sont envoyées par POST, n'oubliez donc pas d'écouter aussi en POST les routes correspondantes
  • C'est idiot mais ne pas oublier de lever la protection CSRF pour l'auto response (par rapport à mon exemple, ce serait "protect_from_forgery :except=>:validate"). Sans quoi l'auto-response ne sera jamais recevable par votre controller. C'est c** mais ça m'a couté 30mn d'arrachage de cheveux :-/.

Vous pouvez m'envoyer un Mail si vous avez des problèmes, je ne garantie rien, mais j'essaierai de répondre.



Commentaires 2 commentaires

Apéro Ruby jeudi 24 Mars à Lyon !


Railers passionnés, développeurs Web de tous horizons et tous niveaux en quête d'infos ou bien simplement curieux à la recherche de développeurs, voila une bonne occasion de rencontrer la communauté Ruby Lyonnaise : Jeudi 24 mars à l'Antre Autre, Lyon 1er (en bas des pentes, à côté de la place Sathonay). Le nombre de participants augmentant rapidement (yes !), nous serons cette fois à l'étage.

Pour ceux qui veulent s'impliquer, ce sera l'occasion de parler des deux gros projets en cours (je n'en dirais pas plus pour le moment), et puis pour tout le monde, c'est l'occasion de boire une bonne bière en parlant de ce qui nous passionne : créer de bonnes et belles applications Web rapidement, de la manière la plus pérenne possible. Tout un programme, hein ?!



Commentaires Aucun commentaire pour le moment

Automatiser des taches récurentes avec Rails


Il existe plusieurs façons d'effectuer des taches récurentes au sein d'une application Rails, notamment avec Rake. La technique que j'utilise présente comme (seul ?) inconvénient d'être un peu lourde puisque elle relance le stack complet lors de son appel. Bon, d'un autre côté, je m'en sert principalement pour les backups et les envois de Mails nocturnes, alors les perfs, dans ce cas, je m'en fout un peu. En revanche, cette technique présente le gros avantage de pouvoir bénéficier de tout Rails (ActiveRecord, ActiveMailer...), et permet aussi d'être intégré au sein de l'appli d'une manière que je trouve plutôt cohérente. Bon, assez parlé, on s'y met :

Créons un répertoire qui contiendra tous les "controllers" de nos tâches nocturnes, nous allons le placer à côté des models et des controllers, appelons le "shedulers"


$ cd /home/mon_appli/app/
$ mkdir shedulers
$ ls
controllers
helpers
models
shedulers
views

Dans ce répertoire "schedulers", créons un fichier -par exemple- "newsletter.rb" (notez l'héritage d'ActiveRecord)

class Newsletter < ActiveRecord::Base

  this_time = Time.now
 
  accounts = Account.find(:all)
   
  accounts.each do |account|
   
    Notifier.deliver_email(account.email,"Newsletter du #{this_time.strftime('%d:%m:%Y')}")  
      
  end
  
end

Hop, vous bénéficiez d'ActiveRecord, vos relations et tout le toutim. Idem pour ActiveMailer, vous avez tout sous la main ! Maintenant, il ne reste plus qu'à appeler notre fichier grâce au script/runner de Rails. Placer vous à la racine de votre appli et taper dans la console :

script/runner app/shedulers/newsletter.rb >> log/production.log 2>&1

Ca marche ? Bon, ben maintenant c'est facile, y'a plus qu'à appeler cette même commande avec Cron

5 3 * * * cd /home/mon_appli && script/runner ./app/crawlers/debiter.rb >> /home/mon_appli/log/production.log 2>&1

Dans cet exemple, la newsletter partira donc chaque nuit à 3h05, et les erreurs éventuelles seront loguées dans le Log habituel de notre appli.



Commentaires Aucun commentaire pour le moment

Meetup Ruby à Chambéry !


Meetup fort agréable ce week-end à Chambéry, dans les locaux de leadformance. Les différents Talks portaient sur l'architecture, JRuby (perso : 'pas encore convaincu de la chose), le caching, la sécurité (toujours interessant comme sujet) et Coffeescript. Etant actuellement en pleine reflexion sur la façon de coder à destination du client, la découverte de Coffeescript est tombée à point nommé. Je pense très probablement m'investir dans cette techno dans les mois qui viennent.

Coté ambiance, c'était vraiment sympa, pas de prise de tête, et des rencontres très interressantes ; en plus des retrouvailles avec (on s'en serait douté) pas mal d'habitués des apéros Rails Lyonnais.



Commentaires Aucun commentaire pour le moment

Dialoguer facilement avec les serveurs de paiement Paybox depuis Rails


Décidement, les Railers Lyonnais font dans la monétique, ces temps ci... Après l'excelllllent plugin pour SIPS/Atos écrit par Damien Mathieu il y a peu, j'ai eu cette semaine à m'interfacer avec cet autre grand prestataire du paiement en ligne Hexagonal qu'est Paybox. A ce propos, juste un petit mot, parce que sans leur aide j'aurais eu du mal, mais la hotline de chez Paybox est remarquable : décroché en 1 sonnerie, réponses pertinentes, numéro non surtaxé... que du bonheur.

Bref, après une soirée à tourner autour de Net:HTTP sur du SSL, j'ai finalement codé une p'tite Class bien pratique pour dialoguer avec Paybox directement et en toute sécurité depuis vos controllers, vous pouvez la télécharger ici.

Concrétement, l'utilisation est super simple : déposez le fichier paybox.rb dans vos modèles, puis il vous suffit d'instancier la classe de cette façon :

# Controller
      response = Paybox.new(
        :operation=>'00003', 
        :amount=>'1000',
        :user_id=>'99', 
        :card_nbr=>'1234567891234567', 
        :expire=>'0311', 
        :cvv2=>'123'
      )

Nous effectuons ici une opération de type '00003' (demande d'autorisation + débit) de 1000 centimes sur notre abonné identifié par l'ID '99', titulaire de la carte '1234567891234567', avec la date de validité au 03/2011 et le code cvv2 '123'.

Maintenant, pour lire la réponse, c'est toujours aussi simple :

# Controller
response.coderesponse = '00000' #=> requete effectuée avec succès
# Ou bien encore : 
response.commentaire = "PAYBOX : Numéro de porteur invalide" #=> Oooops, numéro de carte invalide

Et comme je suis vraiment gentil, j'ai même documenté tous les codes envois/retours de Paybox. Si tout se passe bien, vous n'avez même pas besoin de la doc officielle (au demeurant très bien faite). Bon, par contre, je ne sais pas écrire de commentaires ni de noms de variables autrement qu'en Anglais, et toute la doc (et les variables, WTF !) de Paybox sont en Français pur et dur, alors n'ayez pas peur du Mix Fran-glais...

Edit : Franck a refactorisé et inséré tout ça (en mieux) dans un plugin dispo sur Github.



Commentaires 21 commentaires

Enfin un plugin pour Atos en Ruby


Chaleureuses félicitations à l'équipe de Lyonrb pour sa contribution concernant ce plugin de payment en ligne pour la plateforme Atos. 'Pas encore eu le temps ni l'occasion de tester, mais c'est en tout cas -typiquement- le genre d'outil qui manquait à la communauté Ruby on Rails Française pour rendre crédible notre Framework favori d'un point de vue business/corporate.


Edit : rhoooo, et en prime un apéro prévu ce jeudi à la Croix-Rousse ! Je crois bien que je vais aller y faire un tour...



Commentaires Aucun commentaire pour le moment

Rails + Twitter + OAuth = Twitter gem


Je viens de découvrir ça : twitter gem . Bigre, c'est d'une simplicité déconcertante, et ça marche du tonnerre ! C'est un des aspects de Rails que j'apprécie le plus avec la pratique et le temps : la faculté et la facilité de ré-utilisation du code au travers des Gem et des plugins. Ca permet de gagner un temps fou, tout en s'assurant une qualité optimale.



Commentaires Aucun commentaire pour le moment

Missing the Rails 2.3.5 gem. Please `gem install -v=2.3.5 rails` althought Rails IS already installed


So it appears that Rails apps sometimes boot up strangely... I have a server properly configured that already runs about 5 rails applications, without any single issue ; but as I'm trying to install a copy of Fat Free CRM this morning, the server crashs and application boot fails with this weird message :

Missing the Rails 2.3.5 gem. Please `gem install -v=2.3.5 rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed

I digged a little deeper into it and found that Rails startup is not very verbose nor curious at all : it simply throw out this message whatever could be the error !!! In order to raise the real and specific error that crash you boot, you'll have to edit the /config/boot.rb file, and found these lines :

rescue Gem::LoadError => load_error
 $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
  exit 1
end

Now, add this at the beginning of the rescue block : raise load_error.inspect . This should throw out the real and usable error message.



Commentaires Aucun commentaire pour le moment

Diaspora... et forcément, c'est du Rails !


Si j'en crois le site officiel, le 15 Septembre prochain sera publiée la première release de Diaspora ! J'attend ce projet avec une certaine impatience, parce que l'idée d'un réseau social distribué et open source me trotte dans la tête depuis un bon moment (si vous avez envie de faire de l'archéologie avec du vieux code PHP d'il y a 3 ans, je vous encourage à essayer Com~Unity, appli qui me sert toujours pour mon usage personnel), mais aussi parce que les développeurs du projet ont adopté la techno et les pratiques nouvelles de "développement agile" : Ruby on Rails, Open Source, développement très rapide et versioning avec Github.

Ne serait-ce que pour les choix techniques et le design du site officiel : Diaspora a tout d'une révolution embryonnaire... et c'est peut être -justement- tout ce qu'on en attend qui mènera à sa perte (voir à ce sujet le Post avisé de Jason Fried)



Commentaires Aucun commentaire pour le moment

E-Mail Parsing and manipulation made easy with Astrotrain and Ruby on Rails


Currently working on a CRM project using Fat Free CRM, I needed to handle incoming mails into the machinery. But scanning mails, parse and extract them into plain HTML could really be a pain (I already talked about it...), until I discover Astrotrain ! God damn, another one Rails beautiful Gem/Plugin that just... works !

I love Rails ! (hu ? Did I ever said it yet ?!)



Commentaires Aucun commentaire pour le moment

A powerfull yet simple on the fly thumbnail generator for Ruby on Rails


One of the first thing I need to deal with when I start a project are images, and thumbnail generation is -in my developper point of view- one the key feature of a framework/application. Nonetheless, I found it pretty hard to get a really good thumbnailer as I starded using Rails, so I wrote my own with full caching, img tag attributes and JS events support.

Edit : I finally turned my little helper into a plugin, you should now install it from Github like this :

script/plugin install git@github.com:guillaumedelyon/thumbnail_tag.git

...but anyway, if you want to read about how it works, you can continue reading.

Wanna try it ? Put this code snippet inside one of your helpers (I choosed the main "application_helper")

  def thumbnail_tag(args)
    #On the fly image resizer with cache managment    
    #synopsis = thumbnail_tag(:img=>'path_to_image', :size=>'100xauto' [, :class=>'your_css_class_here', :id=>'id_of_your_img_tag', :title=>'title_of_your_image', :alt=>'alt_attribute', :onclick=>"alert('Hi !')"...])
    
    #Sanity check
    raise 'Thumbnailer error ! Undefined :img parameter in thumbnail_tag helper' if (!args[:img])
    raise 'Thumbnailer error ! Undefined :size parameter in thumbnail_tag helper' if (!args[:size])

    #Get attributes
    options = ""    
    if args[:title] then options << " title='#{args[:title]}'" end
    if args[:id] then options << " id='#{args[:id]}'" end
    if args[:class] then options << " class='#{args[:class]}'" end
    #The alt attribute is automatically picked from the image file name if not explicitly given as an argument
    args[:alt] ? options << " alt='#{args[:alt]}'" : options << " alt='#{args[:img].split('/').last}'"
            
    #Get all other attributes as JS events
    attributes_array = ['img','alt','title','class','id','size']
    args.each do |arg|
      if !attributes_array.include?(arg[0].to_s)  
        options << " #{arg[0].to_s}=\"#{arg[1].to_s}\""
      end
    end
      
    #Create cache dirs if needed
    Dir.mkdir("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}") if !File.directory?("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}")
    Dir.mkdir("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images") if !File.directory?("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images")
    Dir.mkdir("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}") if !File.directory?("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}")
    Dir.mkdir("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}/#{args[:img].split('/')[0]}") if !File.directory?("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}/#{args[:img].split('/')[0]}")

    #Fallback in case something goes wrong later...
    response = "no pic"

    if (resize_array[0] == 'auto' && resize_array[1] == 'auto')
      #Dry picture requested => send back direct link to image, no cache
      response = ""
    end

    if (FileTest.exists?("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}/#{args[:img]}"))
      #We've got it in cache
      response = ""
    end
    
    if (!FileTest.exists?("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}/#{args[:img]}")) && !(resize_array[0] == 'auto' && resize_array[1] == 'auto')
      #File doesn't exists in cache and have to be resized
      require 'rubygems'
      require 'RMagick'
   
      #Image not already in cache ! => resize and write to cache 
      begin
        img = Magick::Image.read("#{RAILS_ROOT}/public/sites/#{request.host.split('www.').last}/medias/images/#{args[:img]}").first
      rescue
        #Ooops, image may have been deleted ?! => fall back on an empty image
        img = Magick::Image.read("#{RAILS_ROOT}/public/images/no_pic.jpg").first
      end
      
      #get requested size
      resize_array = args[:size].split('x')
      width = resize_array[0].to_i if resize_array[0] != 'auto'
      height = resize_array[1].to_i if resize_array[1] != 'auto'
    
      if resize_array[0] == 'auto' 
        #Width is set to 'auto' => compute corresponding X scale
        if img.rows.to_i > height.to_i 
          width = img.columns/(img.rows.to_f/height.to_f)
        else
          width,height = img.columns,img.rows
        end
      end
      
      if resize_array[1] == 'auto'
        #height is set to 'auto' => compute corresponding Y scale
        if img.columns.to_i > width.to_i 
          height = img.rows/(img.columns.to_f/width.to_f)
        else
          width,height = img.columns,img.rows
        end
      end  
    
      #resize
      thumb = img.resize(width,height)
      
      #write it to cache
      thumb.write("#{RAILS_ROOT}/public/cache/#{request.host.split('www.').last}/images/#{args[:size]}/#{args[:img]}")

      #send the image tag pointing on the cached picture
      response = ""
    end
      
    response
  end

Now you can use it like this in your views :

<%= thumbnail_tag(:img=>'/path_to_image/image_name.jpg', :size=>'100xauto') %>

This will generate thumbnail, cache it, then output this to your view :

image_name

Want a height of 200px, with a css class and an onclick event handler ? Simple as pie :

 
<%= thumbnail_tag(:img=>'path_to_image', :size=>'autox200', :class=>'landscape', :onclick=>"alert('hi !')") %>

Full synopsis looks like :

thumbnail_tag(:img=>'path_to_image', :size=>'100xauto' [, :class=>'your_css_class_here', :id=>'id_of_your_img_tag', :title=>'title_of_your_image', :alt=>'alt_attribute', :onclick=>"alert('Hi !')"...])

 

Now, please be carefull about these too things :

  • FIRST OF ALL : WATCH FOR PATH NAMES, as I use a pretty custom file tree in my apps, this surelly won't fit into your own (look about your cache dir !)
  • I actually use ImageMagick to manipulate images, ensure to have it working on your PC

Comments are welcome, but I do not garantee any support.



Commentaires Aucun commentaire pour le moment

Rails 3.0 et Ruby 1.9


Quelques trucs assez surprenants (Mais... pourquoi donc changer la notation des Hash ??!), et plein de bonne choses en perspectives : http://www.slideshare.net/arrrrcamp/ruby-19-and-rails-30



Commentaires Aucun commentaire pour le moment

Calendar_date_select en français et au format 24h


Obtenir des dates correctement formatées dans une interface “user-friendly” est très souvent utile au sein d’une application. Pour arriver à vos fins facilement, rapidement et efficacement, il existe de nombreux Plugins pour Rails. Après en avoir testé plusieurs, j’ai fini par m’arrêter sur Calendar Date Select . Un bon plugin, bien fichu, basé sur la librairie Prototype. Le seul “petit” problème, c’est que la documentation est assez foutraque, les formats de date par défaut sont au format américain “mois/jour/année” et les heures en deux cadrans (5 PM et 5 AM). J’ai donc du me battre avec la doc et creuser dans le code pour arriver à mes fins. Tant qu’à faire, autant partager mes résultats, si ça peut profiter à d’autres…

Note : Ceci n’est probablement pas la solution la plus élégante ni la plus “propre”, mais cela à le mérite de fonctionner parfaitement, et d’être déployable rapidement.

# Installation :

Il est possible d’installer calendar date select via un Gem, mais je préfère le Plugin, afin d’accéder sans souci aux différents fichiers :

git clone git://github.com/timcharper/calendar_date_select.git vendor/plugins/calendar_date_select && rm -rf vendor/plugins/calendar_date_select/.git

Il faut ensuite inclure les fichiers JS dans votre header. Rajoutez la ligne suivante dans votre layout :

<%= calendar_date_select_includes "default" %>

Le “default” représente la skin utilisé, vous pouvez aussi choisir parmi les skins présentes dans votre répertoire “/public/stylesheets/calendar_date_select”

Ajoutez maintenant la ligne suivante dans votre template, en lieu et place de l’emplacement de votre champ date

<%= calendar_date_select_tag "le_nom_de_mon_champ_date", "", :time => true, :style=>'width:220px;' %>

… et hop, vous devriez pouvoir afficher le calendrier au clic sur l’icone à droite du champ. Il ne nous reste “plus qu’à” afficher une date en Français et au format 24h

 

#configuration des jours et des mois :

Nous allons nous baser sur le format “Euro_24h”, le plus proche de celui qu’il nous faut. Ajoutez la ligne suivante dans votre “environmement.rb”

CalendarDateSelect.format = :euro_24hr

Avec ça, le helper que vous avez placé plus haut dans votre header va automatiquement inclure le fichier “/public/javascripts/calendar_date_select/format_euro_24h.js”

Ok, il s’agit maintenant de renseigner les noms des mois et des jours. Editez le fichier “/javascript/calendar_date_select/format_euro_24h” et ajoutez les tableaux suivants :

Date.full_weekdays = $w("Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi");
Date.weekdays = $w("Di Lu Ma Me Je Ve Sa");
Date.months = $w("Janvier Fevrier Mars Avril Mai Juin Juillet Aout Septembre Octobre Novembre Decembre" );

… on ajoute aussi le nom du jour dans le champ date. Remplacez la première ligne de la fonction par celle ci :

str = Date.full_weekdays[this.getDay()] + " " + Date.padded2(this.getDate()) + " " + Date.months[this.getMonth()] + " " + this.getFullYear();

Votre fichier “/javascript/calendar_date_select/format_euro_24h” ressemble donc à ça :

Date.prototype.toFormattedString = function(include_time)
{
  //alert(this.getDay());
   str = Date.full_weekdays[this.getDay()] + " " + Date.padded2(this.getDate()) + " " + Date.months[this.getMonth()] + " " + this.getFullYear();
   if (include_time) { str += " " + this.getHours() + ":" + this.getPaddedMinutes() }
   return str;
}

Date.full_weekdays = $w("Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi");
Date.weekdays = $w("Di Lu Ma Me Je Ve Sa");
Date.months = $w("Janvier Fevrier Mars Avril Mai Juin Juillet Aout Septembre Octobre Novembre Decembre" );

Si vous testez comme tel, vous devriez obtenir un calendrier avec des jours de de type “Lu, Ma, Me…”, et qui vous retourne une date du type “Mardi 1 juin 2010 11:20. C’est déja bien, mais le champ de selection de l’heure est -lui- toujours au format anglo-saxon “AM/PM”. (note : c’est là que ce tuto dérape un peu et est à mon avis un peu “intrusif”, mais bon… si quelqu’un a une solution plus élégante, je suis preneur). Ouvrez maintenant le fichier “/public/javascript/calendar_date_select/calendar_date_select.js”, et éditez les deux méthodes suivante, autour de la ligne 30 :

Date.prototype.getAMPMHour = function() { var hour = this.getHours(); return (hour == 0) ? 12 : (hour > 12 ? hour - 12 : hour ) }
Date.prototype.getAMPM = function() { return (this.getHours() < 12) ? "AM" : "PM"; }

… modifiez les afin d’obtenir ça :

Date.prototype.getAMPMHour = function() { var hour = this.getHours(); return (hour == 0) ? 0 : (hour > 24 ? hour - 24 : hour ) }
Date.prototype.getAMPM = function() { return (this.getHours() < 12) ? "" : ""; }

… et voila !



Commentaires Aucun commentaire pour le moment

Un an avec Ruby on Rails : un bilan approfondi


Celà fait maintenant un an (et une ‘tite quinzaine de jours…) que j’ai découvert Ruby on Rails, et le moment me semble idéal pour faire un vrai bon bilan en profondeur de cette année de travail. Je serais d’abord direct, clair et concis, avant de m’étendre un peu plus dans la conclusion.

# Ce qui est très bien :

- La documentation : oui, je commence directement par ce point, qui me semble es-sen-tiel, et où Rails est tout simplement époustouflant. Grâce à un travail rien moins que monumental de documentation et de vulgarisation, la courbe d’apprentissage est remarquablement courte, et se passe vraiment bien.

- Ruby : au début, je me tournais plutôt vers les Framework PHP genre Cake ou Symphony, par peur d’apprendre encore un nouveau language. En fait, c’est bien le contraire qui s’est passé : j’ai très très vite appris à me débrouiller avec Ruby et tout aussi vite oublié PHP (non, résister à la tentation, ne pas dire du mal des vieux languages plein de rustines… hem…)

- MVC : Modèle, Vue, Controleur. Heuuu, “what else” ?

- RJS : Ajax, en plus d’accélérer les applications (pas besoin de recharger toute la page), apporte un côté ‘bling bling’ dont tous les clients raffolent. Le seul truc, c’est que c’est un peu long et parfois bien tordu à concevoir sans Framework. Avec Rails, les RJS et Prototype, badaboum… on en vient presque à oublier qu’on fait de l’AJAX tellement c’est simple et vite mis en place.

- REST : la façon dont sont implémenté les routes, l’URL rewriting et les interactions avec les controlleurs sont tout simplement gén-iales. Avec RESTfull routing, les adresses sont claires (et courtes !) et vous savez tout de suite ou vous emmène chaque URL.

- I18n : L’internationalisation d’une appli peut vite devenir laborieuse. Aucun souci ici, tout est prévu depuis le départ pour vous simplifier la tâche. Dates, heures, expressions, requêtes… il suffit de respecter une poignée de convention et le Framework s’occupe de toutes vos traductions. Trop pratique !

# Ce qui est bien :

- La souplesse : voila bien un argument contre Rails que j’ai souvent pu lire : “tu es obligé de nommer tes tables d’une certaine façon” ou encore “je veux appeler mes clés étrangères autrement que ‘foreignkey_id’” et autres aneries… En fait, Rails vous pousse juste à utiliser quelques conventions simples afin de vous faire gagner un MAX de temps. Si vous voulez _vraiment_ faire autrement, ou tout simplement que vous devez reprendre un projet existant, il sera toujours extremement simple d’adapter vos propres conventions au sein du Framework. Vous n’avez vraiment aucun souci à vous faire, Rails n’est absolument pas psycho-rigide !

- Active Record : comment parler de Rails sans Active Record ??! Fini les tableaux à 153 dimensions de PHP et le XML des ORM de J2EE. Avec ActiveRecord, tout devient objet, et ridiculement simple à manipuler. Tout simplement génial.

- HAML : alors ça c’est un effet de bord assez inattendu. Découvert par hasard avec le plus grand des dubitatismes (ne me parlez pas de Smarty et autre PHP template…), j’ai finalement adopté sans aucune réserve ce language de template. Je retrouve enfin la lisibilité de Python, même avec des mises en pages franchement complexes bourrées d’AJAX, le template reste clair et limpide. Comme tout ce qui tourne autour de Rails, le temps d’apprentissage est ultra court, et l’essayer c’est l’adopter ! Note : il parait qu’il existe des bindings pour PHP, à voir…

# Ce qui est moins bien :

- Mauvais cross platform. Oui, il existe bien un genre de Wamp/EasyPHP pour Windows (Instant Rails), qui est très pratique pour découvrir Rails et faire ses premiers pas, mais on en trouve très-très vite les limites. Si vous voulez éviter toute surprise dans le déploiement de votre appli, et souhaitez profiter pleinement d’un environnement serveur puissant et souple, il vous faut une base Unix. Mac ou Linux ou BSD ou ce que vous voulez, mais pas Windows.

- L’hébergement : le mutualisé avec Rails, ça n’existe pas. Ou alors, c’est pas terrible et de toute façon toujours trop cher. Pour disposer d’une plateforme fiable et sérieuse, vous devrez obligatoirement vous acquitter d’au moins une quarantaine d’euros/mois pour un VPS, et vous taper l’install à la mano qui va avec. Si vous ne connaissez rien à la maintenance d’un serveur dédié sous Linux, ça va être le moment de vous y mettre…

- C’est lent. (soupir…) j’aurais tellement aimé vous dire que c’est faux, mais, malheureusement : non. C’est lent. Bon, ‘faut toujours comparer ce qui est comparable, c’est ni plus ni moins lent qu’un autre Framework et face à Cake ou Django, on est dans les clous, ni mieux ni pire. Par contre, ne pas perdre de vue qu’il va falloir oublier les hébergement à 50 Euros/an tournant avec 512 Mo de RAM. Ceci étant, les fonctionnalitées de cache sont vraiment rapides et diablement efficaces à déploier. Pour peu que votre appli ne soit pas trop exigeante en terme d’interactivité, au final, il y a la possibilité d’égaler les perfs d’une page HTML statique (si, si…)

# En conclusion :

Rails est parfait si :

- Vous voulez proposer rapidement une appli type SaaS et vous disposez de ressources hyper limitées. Ce qui était d’ailleurs exactement le cas de figure lorsque DHH a créé le Framework, et qui est aussi mon cas.

Rails est très bien si :

- Vous cherchez une nouvelle techno pour remplacer le socle de travail de base de votre entreprise. Puissant, structurant, avec un environnement de tests unitaires, I18n, Open Source… J’entends et lis souvent que Rails est le futur “J2EE Killer”. Vous voulez mon avis ? C’est très probablement vrai.

- Vous avez toutes les casquettes et cherchez un couteau suisse pour des développements Web vite-faits/bien-faits dans des projets courts et “one-shot”.

Rails ne répond pas à vos besoins si :

- Votre but est de gagner rapidement de l’argent en répondant à un besoin ultra courant. Typiquement : du E-Commerce ou du site vitrine à la chaine. Dans ce cas, restez avec Joomla ou Wordpress et ne vous embarquez pas dans de longs et couteux développements sur-mesure, ça ne sert vraiment à rien de chercher midi à 14 heures (sauf pour la beauté du geste, bien sur, mais j’ai dit “gagner de l’argent”, et pas “se faire plaisir”. Ceci dit, à vous de voir…).

Voila pour ce bilan, j’espère vous avoir donné envie de découvrir ce merveilleux environnement de travail, qui ne cesse de m’impressionner par son côté pragmatique, et qui me permet de coder 3 à 4 fois plus vite qu’en PHP. Ce qui était avant hors de porté pour un developpeur seul est devenu tout à fait possible, et je peux désormais me concentrer pleinement sur le fond : le Design, l'interactivité des interfaces et les aspects métiers de chaque application.



Commentaires Un commentaire

Ruby Entreprise Edition : résultat du test (ou : l’essayer c’est l’adopter)


Finalement, les choses sont allées beaucoup plus vite que prévu concernant mes essais avec REE. Tout d’abord, la facilité d’installation (voir ici pour toutes les explications, mais vraiment rien de sorcier, ni de risqué). Une fois installé (15mn, en comptant Rails et les Gems qu’il faut ré-installer aussi), il ne m’a pas fallu très longtemps pour me décider. J’ai simplement utilisé mon bon vieux test à base de siege en local sur ma machine de test :

  • Linux 2.6.31-16
  • Pentium Dual core @2.10 GHz
  • 4 Go de RAM
  • Apache/2.2.12 avec Phusion Passenger

J’ai donc requeté 5 URL cibles pendant une minute et voila ce qui en ressort :

# Avec Ruby 1.8

Transactions:                 698 hits
Availability:              100.00 %
Elapsed time:               59.32 secs
Data transferred:            1.41 MB
Response time:                0.76 secs
Transaction rate:           11.77 trans/sec
Throughput:                0.02 MB/sec
Concurrency:                8.95
Successful transactions:         705
Failed transactions:               0
Longest transaction:            2.23
Shortest transaction:            0.02

Avec un top la dessus au passage, ça nous donne :

Cpu(s): 90.5%us,  9.1%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.2%hi,  0.2%si,  0.0%st
Mem:   3574984k total,  1937232k used,  1637752k free,   119544k buffers

 

# Maintenant, on passe le turbo avec la Entreprise Edition :

Transactions:                 844 hits
Availability:              100.00 %
Elapsed time:               59.63 secs
Data transferred:            1.71 MB
Response time:                0.54 secs
Transaction rate:           14.15 trans/sec
Throughput:                0.03 MB/sec
Concurrency:                7.68
Successful transactions:         856
Failed transactions:               0
Longest transaction:            2.60
Shortest transaction:            0.01

La sortie du top :

Cpu(s): 86.3%us,  7.9%sy,  0.0%ni,  5.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   3574984k total,  1773884k used,  1801100k free,   119200k buffers

Bien, voila pour les chiffres, qui sont déja assez parlant. Maintenant, si je relance la même manip, mais au lieu de regarder bêtement le déroulement du test, j’utilise l’appli en même temps que siege pour voir comment le bidule se comporte et si ça reste utilisable malgré les 800-et-quelques requêtes par minutes. Le résultat est sans appel : la Entreprise Edition apporte une fluidité vraiment remarquable et très, très sensible.

Conclusion : Je test encore toute la semaine histoire d’être absolument certain de la fiabilité et de la compatibilité avec Ruby 1.8, et puis je bascule les serveurs de prod sous REE.

On peut le dire : je suis 100% convaincu.



Commentaires Aucun commentaire pour le moment

A Ruby Gateway for Postfix (in order to build a Rails Webmail)


Edit : This code is globally out of date and pretty hazardous... I now use the awesome Astrotrain plugin to retrieve E-Mails into Ruby on Rails' apps, but feel free to read my blog post anyway :-)

Well, it took me almost two weeks to get the whole thing to work, and regarding to the poorly documentation I have had to deal with, I think it could be a good idea to share this experience.

The goal is to retrieve incoming and outgoing mail from Postfix, then push them into a Database. First of all, let’s configure Postfix. I assume you already have a working installation of Postfix. Postfix uses the “vmail” user (yes, I use the MySQL virtual Mail package).

Add this to your /etc/postfix/master.cf :

mail_filter unix -     n       n       -       -       pipe
 flags=hq user=vmail argv=/usr/bin/ruby1.8 /var/spool/filter/mail_filter.rb

smtp      inet  n       -       -       -       -       smtpd
 -o content_filter=mail_filter:

Now, every mail (incoming AND outgoing!) will be “piped” to the /var/spool/filter/mail_filter.rb Ruby script. By the way, I could -of course- have used any language like Shell or Perl, but I read some interesting docs about Tmail, and I now really love Ruby, so… why not ?

First, you’ll need a Mail parser to read the mail content : install TMail

sudo gem install tmail

Ok, let’s create this Ruby filter, we’ll store it where we just told to Postfix to look at

/var/spool/vmail/mail_filter.rb

And now, let’s read mails !

#Read the message
message = $stdin.read
#Parse it
mail = TMail::Mail.parse(message)

…easy, hu ? Now, let’s see what’s inside this mail

#Extract what we need...
from_list = "" #the "from" field is also an array 
mail.from.each do |addr|
  from_list.length > 1 ? from_list << addr + "," : from_list << addr
end        

to_list = ""
mail.to.each do |addr|
  to_list.length > 1 ? to_list << addr + "," : to_list << addr
end

if mail.cc != nil 
  cc_list = ""
  mail.cc.each do |addr|
    cc_list.length > 1 ? cc_list << addr + "," : cc_list << addr
  end
end

if mail.bcc != nil
  bcc_list = ""
  mail.to.each do |addr|
    bcc_list.length > 1 ? bcc_list << addr + "," : bcc_list << addr
  end
end

Every mail now piped to the Mail Filter, WE DO HAVE to handle file writing if we want to retrieve mail using pop3 ! Skip this if you don’t want to duplicate mails to the filesystem and in the DB

#Get the domain name
@domain_name = to_list.split('@')[1]

#Write the mail to the file system so we still can access it via pop3
myFile = File.open("/var/spool/vmail/#{@domain_name}/#{to_list.split('@')[0]}/new/#{Time.now.to_i}", "w")
myFile.write message
myFile.close

DB Connection. I use the exact domain name for the database name as convention, this now allow me to link the mail to the proper database.

# connect to the MySQL server, Warning : The domain name MUST BE the same as DB name
begin
  dbh = Mysql.real_connect("localhost", "DB_user", "DB_password", @domain_name.split('.')[0])     
rescue
  Process.exit
end

And now we insert the mail body, assuming this is a simple text mail

if mail.parts.length == 0
  #no attachment, only a text body
  req = dbh.query("INSERT INTO emails (filename,from_field,to_field,cc_field,cci_field,subject,content,created_at,updated_at,status,direction,email_account_id) 
              VALUES (
              'nom de fichier',
              '#{from_list}',
              '#{to_list}',
              '#{cc_list}',
              '#{bcc_list}',
              '#{mail.subject}',
              '#{mail.body}',
              now(),
              now(),
              'new',
              'incoming',
              '1')
              ")

But, what about attachments ?! Hehe… this part is quite a bit F***** tricky and causes me some headaches because of the lack of documention

  
else
  #email.attachments are TMail::Attachment
  #but they ignore a text/mail parts.
  @i = 0
  @email_id = 0
  mail.parts.each_with_index do |part, index|
    if @i == 0
      #Push mail text body into DB
      req = dbh.query("INSERT INTO emails (filename,from_field,to_field,cc_field,cci_field,subject,content,created_at,updated_at,status,direction,email_account_id) 
                  VALUES (
                  'nom de fichier',
                  '#{from_list}',
                  '#{to_list}',
                  '#{cc_list}',
                  '#{bcc_list}',
                  '#{mail.subject}',
                  '#{part.body}',
                  now(),
                  now(),
                  'new',
                  'incoming',
                  '1')
                  ")
    else
      filename = (part['content-location'] && part['content-location'].body) || part.sub_header("content-type", "name") || part.sub_header("content-disposition", "filename")

      #get email_id and create the sub dir for attachments
      if @email_id == 0 
         @email_id = dbh.insert_id()
         system "mkdir /home/guillaume/#{@domain_name.split('.')[0]}/tmp/attachments/#{@email_id}"
         system "chmod -R 0770 /home/guillaume/#{@domain_name.split('.')[0]}/tmp/attachments/#{@email_id}"
      end
      
      dbh.query("INSERT INTO attachments (created_at,updated_at,filename,email_id,content_type)
                VALUES (
                now(),
                now(),
                '#{filename}',
                #{@email_id},
                '#{part.content_type}'
                )
      ")
      #write attachments to the file system
      File.open("/home/guillaume/#{@domain_name.split('.')[0]}/tmp/attachments/#{@email_id}/#{filename}",File::CREAT|File::TRUNC|File::WRONLY,0777) do |f|
        f.write(part.body)
        system "chmod 0770 /home/guillaume/#{@domain_name.split('.')[0]}/tmp/attachments/#{@email_id}/#{filename}"
      end    
    end
    @i += 1
  end
end

And voila ! As you can see, I store Attachments on the filesystem, this is my own way to do things as I do hate to insert huge blobs into Databases, but do what you want…

You can retrieve the whole script here and adapt it to you needs, hope this could help…



Commentaires Aucun commentaire pour le moment

RubyPants : Le Saint Graal de l’apostrophe et du Guillemet


Bien prendre en charge les guillemets et autres apostrophes situé dans le contenu d’un site est un truc qui n’a vraiment l’air de rien, semble parfaitement naturel, et qui peut pourtant -en tant que développeur- vous rendre complétement dingue ! En effet : tout language de programmation utilise lui aussi, ces mêmes guillemets et apostrophes, et bien souvent “language de programmation” et “phrase entre guilletmets” se chevauchent et s’entremêlent finement. Si en plus, vous avez un minimum d’élégance et que vous utilisez de beaux guillemets différents pour la gauche (“) et la droite (”), le problème prend rapidement de l’épaisseur.

Après des années de bricolage en PHP, j’ai ENFIN trouvé une solution avec Ruby, robuste et diablement efficace : RubyPants

La documentation étant inexistante, je me fends d’un micro tuto, adapté à Rails :

Placez le fichier RubyPants.rb dans le répertoire /lib

Dans le controller contenant votre insertion de contenu dans la BDD, ajoutez tout en haut :

require ’RubyPants’

Dans la méthode qui doit insérer le contenu, instanciez votre classe avec votre chaine en argument :

my_string = RubyPants.new(’Ceci est une phrase “entre guillemets“)

Et voila ! Maintenant, si vous appellez votre chaine de caractère avec la méthode “to_html“, vous obtenez :

my_string.to_html => Ceci est une phrase “entre guillemets”


Commentaires Aucun commentaire pour le moment

Ruby on Rails VS Java vs C++ vs Assembler


Un très bon article [En] résumant tout à fait mon point de vue quant à la lenteur de Ruby. Le cycle de CPU est chaque jour de moins en moins cher, alors que la charge horaire d’un développeur est toujours aussi élevée. Les temps changent, les CPU n’ont plus rien de commun avec ce qu’elles étaient il y a dix ans, idem pour la RAM : il est temps d’améliorer la productivité en sautant un niveau d’abstraction dans la conception des applications, et Ruby (on Rails) est un formidable outil pour faire ce bond et gagner un temps précieux.



Commentaires Aucun commentaire pour le moment

Calcul sur des plages de temps en Rails


Admettons que je veuille connaitre la somme totale de toutes les commandes effectuées entre le 1er et le 15 Septembre 2009. Je ne sais pas comment les choses se passent en PHP avec Cake ou Symphony, mais avec Rails, c’est d’une simplicité à tomber par terre :

Payment.sum(’amount’, :conditions=>[“created_at BETWEEN ’2009-09-01’ and ’2009-09-15’“])

Hein ?! Oui, c’est tout. Voila, Fini. J’ai le temps d’aller me reservir un café et de me pencher sur la maquette graphique de mon nouveau client :-)

Non mais, sans rire, comment on faisait avant les Frameworks ?!



Commentaires Aucun commentaire pour le moment

Installer Ruby on Rails chez OVH en 5mn chrono


Vous avez un serveur dédié (RPS dans mon cas) sous Ubuntu (je suppose que c’est pareil pour Debian), et vous avez envie d’y installer Ruby on Rails ? Bonne idée ! D’autant que c’est vraiment pas compliqué


Tout d’abord, fuyez les versions installées via apt-get et faites un apt-get remove –purge de tout ce qui peut concerner ROR de près ou de loin. Maintenant, pour TOUT ce qui va suivre, restez en Root.

# On commence par n’installer “que” Ruby (ce sera notre seule et unique utilisation d’apt) avec :

apt-get install ruby-full

#Ensuite, télechargez ruby-gems depuis ruby forge et SURTOUT, NE VOUS SERVEZ PAS DE LA VERSION APT, où alors, c’est que vous avez vraiment envie de vous amuser 4/5 heures avec des problèmes de dépendance (je sais de quoi je parle…). Ensuite comme d’hab :

tar zxvf rubygems-1.3.4.tgz

Faites bien l’extraction du Tar.gz en Root, il pourait y avoir des problèmes de droits ultérieurs.

#Installez maintenant Ruby-gems :

cd rubygems-1.3.4.tgz
ruby setup.rb

Chez moi (en local et sur le serveur), j’ai un warning à la fin à cause d’une doc non trouvée : on s’en fout. Une fois l’install terminée, vous pouvez aussi supprimer l’archive tar.gz ainsi que le répertoire “rubygems-1.3.4” qui va avec.
Bien, maintenant, chose étrange, si vous tentez tout de suite de faire un

gem install rails

Vous allez vous retrouver avec un assez effrayant “commande introuvable“. Pas de panique, c’est juste que la commande “gem” s’appelle dans un shell avec “/usr/bin/gem1.8“.

# Créez un alias dans votre .bashrc

alias gem = /usr/bin/gem1.8

Vous y êtes !

gem install rails

5 petites minutes à attendre… et vous voila avec une version 2.3.2 tout neuve et clinquante.

#Il ne reste plus qu’à installer Passenger pour faire tourner tout ça dans Apache2 :

gem install passenger
passenger-install-apache2-module

#Sans oublier RMagick pour manipuler des images tant que nous y sommes :

 

gem install rmagick

Rien de compliqué, en fait, le truc c’est de :
- ne pas utiliser Apt en dehors de l’install de Ruby
- bien télécharger ruby-gems depuis Ruby forge
- ne pas trop être surpris par le “commande introuvable” après l’install de Rub-gems



Commentaires Aucun commentaire pour le moment

Le Controler maigre et le gros Model


Excellent article de Jamis Buck, aussi clair qu’accessible, et pourtant pointu.



Commentaires Aucun commentaire pour le moment

Besoin d’aide pour les Regex en Ruby ?


Les Regex et moi, ça fait deux. Rien n’est pire pour moi que de voir se rapprocher inexorablement le moment ou je vais devoir y passer… Je viens toutefois de découvrir l’outil idéal pour me réconciler avec les %r{(d+)(/|:)(d+)(/|:)(d+)} et autres réjouissances, ça s’appelle Rubular et ça se trouve ici : http://www.rubular.com/ .

A cela vous ajoutez l’exceeeeellent Paul’s Ruby Regex Primer, et vous voila armé pour faire face à tous vos besoins, en toute quiétude.

Les Regex en Ruby ? Même pas mal.



Commentaires Aucun commentaire pour le moment

Subsctruct : un CMS en Rails


Je viens de découvrir ça : http://code.google.com/p/substruct/ et ça me plait _vraiment_ beaucoup. J’avoue ne pas avoir été trop emballé par les trucs comme Adva CSM (UI trop avant-gardiste ?) ou Radiant, mais Substruct, là, vraiment, ça rocks.

C’est incroyable comme Rails permet de prendre en main en quelques minutes seulement une application aussi complexe que peut l’être du E-Commerce couplé à un CMS. Quand je repense aux plats de spaghettis que peuvent être les Wordpress et autres Joomla, beurk, vraiment, le PHP c’est fini pour moi… Rails Rules !



Commentaires Aucun commentaire pour le moment

Pourquoi Rails ?


J’avais survolé le sujet il y a peu alors que je faisais le point après un mois passé à développer du Rails, il est temps maintenant de m’expliquer un peu : pourquoi donc Rails et pas Cake, Symphony ou Django ?

Tout d’abord, j’en avais marre des points virgules, des accolades et du modèle objet boiteux. Voila, comme ça, c’est clair. J’ai beaucoup aimé PHP des années durant (le côté “rustine/4x4/passe partout“), mais… en quelques lignes de Ruby, l’affaire était entendue. TOUT y est plus simple, plus “logique“. J’ai lu que beaucoup de développeurs PHP utilisaient Cake ou Symphony par peur de Ruby. Franchement, dans mon cas, c’est plutôt l’inverse, c’est bien Ruby qui m’a attiré vers Rails et m’a vite fait oublier Cake, PHP (et les points virgules).

Ha, Cake PHP… tout pour plaire effectivement, quoique pour ce que j’en ai vu, cela me semble bien être une copie conforme de Rails, sans Ruby, ni ActiveRecord :-(. Pour Symphony, j’ai pas aimé. Bon, j’avoue ne pas avoir creusé plus d’une après midi, mais j’ai pas aimé. La Doc, le générateur d’Admin, Propel… rien ne m’a fait dire “Whaouuu, je veux ce truc !“. Donc, bon, bof, au revoir. Concernant Jango, il y avait d’emblé un sacré poid dans la balance : Python ! Pensez donc : mon premier language, avec lequel j’aimerais avoir à faire plus souvent que pour quelques rares scripts sous Linux. Bon, là, par contre, ça m’a paru un sacré engin à mettre en place. Après une demi-heure à batailler pour l’installation, j’ai commencé le premier tuto. 1 heure, deux heures… toujours pas UNE page Web !!!

Puis j’ai tenté Rails, dont un collègue lors de mon court passage chez SEB m’avait fait l’éloge. Sans guère plus d’a priori que pour les 3 autres Framework précedemment testés, tatonnant, suivant la logique habituelle, et sans même un seul tuto , j’ai pu obtenir une appli utilisable… en moins de 5mn montre en main, installation comprise. Oui, j’avoue, j’était sur le c***. La suite n’a été qu’un déroulement logique de ce début prometteur. Aujourd’hui, je ne compte plus le nombre de fois où je me suis dit “heuuu, bon, ça j’ai jamais fait, mais ça peut quand même pas être aussi simple que ça… je tente ? et….” et ça marche !!!

Bref, en un mot comme en cent : un Framework est sensé vous faire gagner du temps et améliorer la qualité de votre code. Que ce soit avec Cake, Symphony ou Django, je passais mon temps à me demander quelle forme pouvait bien avoir la courbe d’apprentissage avant de pouvoir maitriser de tels outils. Avec Rails, je me fiche de la courbe d’apprentissage : je code et en plus, ça marche. Tout de suite. Comme diraient certains… What else ?



Commentaires Aucun commentaire pour le moment

Un mois avec Ruby on Rails : un premier bilan


Voila donc maintenant un mois que je me suis jeté dans le développement avec Ruby On Rails. Pourquoi Ruby on Rails et pas cake PHP ? Ou alors Symphony ? Django ? Il y a plusieurs raisons sur lequelles je ne manquerai de revenir dans un futur post, mais je voulais aujourd’hui établir un premier bilan de ce mois de Mai, profondément “immergé dans les rails“, et donner mon modeste point de vue, ainsi que quelques conseils.

Tout d’abord : parlez Anglais !!! Tout, absolument TOUT est en Anglais. Il y a bien (eu ? je peux parler au passé ?!) un site francophone dédié à Rails, mais il me semble bien moribond quant on voit le foisonnement Anglo-saxons.

Laissez tomber les bouquins, et inscrivez vous sur les forums. Oui, je dis ça, bon, je suis un peu énervé, mais ayant acheté “Ruby on Rails, rapide et efficace“, j’avoue avoir été assez décontenancé lorsque les exemples fournis dans le bouquin… ne fonctionnèrent tout simplement pas. Ecrit pour Rails 1.2, Beaucoup d’évolutions ont été amenées avec la version 2.0, et pas “back compliant” du tout, les évolutions ! Dans le même genre, faites _toujours_ attention aux dates lorsque vous lisez des blogs ou des tutos. Les problèmes de version sont vraiment casse-pieds, c’est un défaut que je reconnais volontier (ha… la jeunesse).

Inscrivez vous sur http://railsforum.com/ : une mine de renseignements, et des gens toujours prêts à vous aider, avec une spontaneité remarquable. Même si vos questions peuvent paraitre vraiment simplettes, les réponses sont toujours courtoises et efficaces.

N’ayez pas peur de Ruby, venant de PHP, j’avais naturellement peur de franchir le pas d’un nouveau language. En fait, c’est plutôt l’inverse qui s’est produit : je suis devenu accro et retourner dans du PHP pour la maintenance des anciens site est devenu une véritable plaie !

Laissez tomber le scaffolding. Ok, on peut faire une appli de liste de course ou un livre de cuisine en 2 lignes de commande (si, si, c’est vrai), mais bon, il faut être honnête, une vrai application c’est quand autrement plus complexe et “profond“. Je vous rassure, tout coder à la main n’a rien, mais alors vraiment rien de compliqué, suffit de passer un peu de temps à se familiariser avec les “helpers” dans les vues. Quant à la partie “activeRecord“, qui remplace le traditionnel SQL dans les requêtes… c’est du pur bonheur et ça s’apprend en une après midi (Hein ? Si !)

Enfin, pour finir, je n’aurai qu’un seul mot : l’essayer c’est l’adopter. Il m’avait fallu plusieurs mois, après des années de PHP, pour coder un CMS maison, avec des fonctionnalitées somme toute assez limitées, il a suffit d’un mois (UN MOIS !) pour obtenir un CMS bien plus complet, permettant par exemple des fonctionnalitées de E-Commerce intégrées, et bénéficiant d’un potentiel en éventuelles nouvelles fonctionnalités sans commune mesure, sans compter la fiabilité apportée par l’environnement de tests unitaires de Rails…

Je suis plus que séduit par Ruby On Rails : je suis complétement conquis. Encore quelques semaines de rodage et notre offre commerciale sera entièrement tournée vers des produits en Rails. Quant à PHP… Je le dis ? Allez, allons-y : “PHP, ça craint“.



Commentaires Aucun commentaire pour le moment