Ce blog — désormais archivé — est en lecture seule. Rendez-vous sur mon nouveau site personnel.

Prendre un Café

L'espace d'expression de Nicolas Perriault

Aller au contenu | Aller au menu | Aller à la recherche

Ruby

Ma découverte du langage Ruby et du framework Ruby-on-Rails.

Fil des billets

samedi 3 mars 2007

Ruby on Rails 1.2.2, les migrations

Voici la suite du précédent tutoriel sur Ruby on Rails publié sur ce même blog ou nous avons mis en place une application de gestion de contacts rudimentaire.

Migration de schéma de base de données

Imaginons que nous voulions gérer une liste de sociétés, et lier chacun de nos contacts à sa société... Il va nous falloir modifier notre base de données en ajoutant une table companies et une clé company_id dans la table contacts. Cela peut s'avérer compliqué puisqu'elle contient déjà des données... même si en l'occurence il ne s'agit pour l'heure que de données de test.

Rails et plus particulièrement ActiveRecord proposent un outil de gestion des évolutions du modèle de données intelligent, les migrations. Au même titre que nous avions créé le fichier db/migrate/001_contacts_development.rb pour définir le schéma initial lors du tutoriel précédent, nous allons maintenant créer son évolution incrémentale dans le fichier db/migrate/002_contacts_development.rb :

 ruby
class ContactsDevelopment < ActiveRecord::Migration
  
  def self.up
    # On renomme le champs name en first_name (ne devra contenir que le prénom)
    rename_column :contacts, "name",       "first_name"
    
    # Ajout d'un champs pour stocker le nom de famille
    add_column    :contacts, "last_name",  :string
    
    # Ajout d'un champs pour stocker la société du contact
    add_column    :contacts, "company_id", :integer
    
    # Création de la table des sociétés
    create_table "companies", :force => true do |t| 
      t.column "name",        :string
      t.column "description", :text
      t.column "url",         :string
    end 
  end 

  def self.down
    # Rétablissement de la colonne name
    rename_column :contacts, "first_name", "name"

    # Destruction de la colonne last_name
    remove_column :contacts, :last_name
    
    # Destruction de la colonne contenant la référence à une société
    remove_column :contacts, :company
    
    # Destruction de la table contenant les sociétés
    drop_table :companies
  end 

end

Dans chaque classe de migration de schéma, une méthode up appliquera des modifications au modèles tandis qu'une méthode down permettra un rollback des modifications vers une version antérieure. Pour le détail des opérations effectuées par le script de migration ci-dessus, je crois que les commentaires parlent d'eux-mêmes ;) (j'en ai profité pour répartir le patronyme sur deux champs, nom et prénom)

La mise à jour effective du modèle dans la base de données s'effectue grâce à la commande :

 bash
$ rake db:migrate 
(in /home/niko/ww2/rails/contacts)
== ContactsDevelopment: migrating =============================================
-- rename_column(:contacts, "name", "first_name")
   -> 0.0750s
-- add_column(:contacts, "last_name", :string)
   -> 0.0153s
-- add_column(:contacts, "company_id", :integer)
   -> 0.0343s
-- create_table("companies", {:force=>true})
   -> 0.0304s
== ContactsDevelopment: migrated (0.1694s) ====================================

Nous n'avons pas d'outils d'administration pour notre nouvelle table companies, créons-les :

$ ruby script/generate scaffold Company

Il faut maintenant mettre à jour notre jeu de données ; on édite d'abord le nouveau fichier ./test/fixtures/companies.yml :

 yaml
Nanonical:
  id:          1
  name:        Nanonical
  description: On vous préfère libres
  url:         http://www.nanonical.com
  
Crimosoft:
  id:          2
  name:        Crimosoft
  description: Notre monopole, c'est trop lol
  url:         http://www.crimosoft.com

Toute ressemblance avec des sociétés existantes ou ayant existé serait un sacré coup de pot

Puis, dans le fichier ./test/fixtures/contacts.yml :

 yaml
John:
  id:         1
  first_name: John
  last_name:  Doe
  email:      john@doe.com
  address:    12, rue des champs
  zip:        75009
  city:       Paris
  country:    France
  company_id: 1 # John -> Nanonical
 
Bob:
  id:         2
  first_name: Bob 
  last_name:  Doe 
  email:      bob@doe.com
  address:    1, place du pré 
  zip:        35000
  city:       Rennes
  country:    France
  company_id: 2 # Bob -> Crimosoft

On réinsère nos nouvelles fixtures :

$ rake db:fixtures:load

On peut se rendre successivement aux adresses http://0.0.0.0:3000/contacts et http://0.0.0.0:3000/companies afin de s'assurer que tout va bien.

companies_scaffolding.png

Mise à jour des classes modèles

Pour que Rails prenne en compte les modifications structurelles de notre schéma, nous allons éditer les fichiers des modèles Contact et Company, notamment pour spécifier leur type de relation grace aux méthodes de classe ActiveRecord.

Le fichier ./apps/models/contact.rb :

 ruby
class Contact < ActiveRecord::Base
  # Chaque employé appartient à une compagnie
  belongs_to :company
end

Et le fichier ./apps/models/company.rb :

 ruby
class Company < ActiveRecord::Base
  # Une société possède plusieurs employés
  has_many :contact
end

Mise à jour du contrôleur

On récupère la liste des sociétés depuis le contrôleur gérant les contacts (situé dans le fichier ./app/controllers/contacts_controller.rb), d'abord pour la création :

 ruby
class ContactsController < ApplicationController
  [...]
  def new
    @contact = Contact.new
    @companies = Company.find_all
  end

Puis pour l'édition:

 ruby
class ContactsController < ApplicationController
  [...]
  def edit
    @contact = Contact.find(params[:id])
    @companies = Company.find_all
  end

Mise à jour de la vue

Enfin, modifions notre formulaire d'édition/création de contacts, situé dans app/views/contacts/_form.rhtml, comme suit :

 rhtml
<%= error_messages_for 'contact' %>

<!--[form:contact]-->
<p><label for="contact_company_id">Company</label>
<%= select 'contact', 'company_id', @companies.collect {|c| [c.name, c.id]} %></p>

<p><label for="contact_name">First name</label><br/>
<%= text_field 'contact', 'first_name'  %></p>

<p><label for="contact_name">Last name</label><br/>
<%= text_field 'contact', 'last_name'  %></p>

<p><label for="contact_email">Email</label><br/>
<%= text_field 'contact', 'email'  %></p>

<p><label for="contact_address">Address</label><br/>
<%= text_field 'contact', 'address'  %></p>

<p><label for="contact_city">City</label><br/>
<%= text_field 'contact', 'city'  %></p>

<p><label for="contact_zip">Zip</label><br/>
<%= text_field 'contact', 'zip'  %></p>

<p><label for="contact_country">Country</label><br/>
<%= text_field 'contact', 'country'  %></p>
<!--[eoform:contact]-->

Ce qui donne à peu-près ceci :

Nouveau formulaire de création/édition de contacts

Et le template d'affichage de notre liste de contacts, dans le fichier ./app/views/contacts/list.rhtml pour y ajouter la colonne affichant le nom de la société pour chaque contact :

 rhtml
<h1>Listing contacts</h1>

<table>
  <tr>
  <% for column in Contact.content_columns %>
    <th><%= column.human_name %></th>
  <% end %>
    <th>Société</th>
  </tr>
  
<% for contact in @contacts %>
  <tr>
  <% for column in Contact.content_columns %>
    <td><%=h contact.send(column.name) %></td>
  <% end %>
    <td><%= h contact.company.name %></td>
    <td><%= link_to 'Show', :action => 'show', :id => contact %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => contact %></td>
    <td><%= link_to 'Destroy', { :action => 'destroy', :id => contact }, :confirm => 'Are you sure?', :method => :post %></td>
  </tr>
<% end %>
</table>

<%= link_to 'Previous page', { :page => @contact_pages.current.previous } if @contact_pages.current.previous %>
<%= link_to 'Next page', { :page => @contact_pages.current.next } if @contact_pages.current.next %> 

<br />

<%= link_to 'New contact', :action => 'new' %>

Ce qui donne au final quelque chose comme ceci :

Nouvelle liste de contacts

To be continued

Dans un prochain tutoriel, nous aborderons la validation de formulaires.

samedi 3 mars 2007

Ruby on Rails 1.2.2, premier contact

Je dois préparer une réunion technique sur Ruby on Rails, aussi je m'y remets doucement. J'en profite donc pour passer en revue la version 1.2.2 du framework par le biais d'un petit tutoriel. Je prends pour exemple la gestion d'un carnet d'adresses simplissime.

Installation sur Ubuntu

L'installation de rails sur Ubuntu est toujours aussi simple.

Création de l'application

Vos pouvez créer votre projet rails n'importe où sur votre disque dur, par exemple dans ~/rails :

$ cd ~ && mkdir rails
$ rails contacts

Le squelette de l'application contacts est créé sous la forme d'un répertoire contenant l'arborescence par défaut d'un projet vierge.

$ cd contacts

Pour tester votre projet vierge, vous pouvez lancer Webrick, un petit serveur HTTP écrit en ruby inclus dans les librairies du framework :

$ script/server

Faites pointer votre navigateur à l'adresse http://0.0.0.0:3000/ pour admirer la page par défaut du projet.

Capture d'écran

Configuration de l'accès aux données

Dans le fichier config/databases.yml, on définit nos paramètres de connexion au SGBD, ici MySQL :

 yaml
development:
  adapter:  mysql
  database: contacts_development
  username: root
  password: password
  host:     localhost
  socket:   /var/run/mysqld/mysqld.sock

N'oubliez pas de créer une base MySQL contacts_development, hein ;)

Création d'une table dans la base données

On va utiliser le système de migration propre à rails pour garantir une évolutivité de notre modèle de données :

$ ruby script/generate migration contacts_development

On édite le fichier généré dans db/migrate/001_contacts_development.rb :

 ruby
class ContactsDevelopment < ActiveRecord::Migration

  def self.up
    create_table "contacts" do |t| 
      t.column "name", :string
      t.column "email", :string
      t.column "address", :string
      t.column "city", :string
      t.column "zip", :string
      t.column "country", :string
    end 
  end 

  def self.down
    drop_table :contacts
  end 

end

On lance la migration, ce qui pour l'heure aura pour conséquence et pour l'heure de créer notre table contacts dans la base de données :

$ rake db:migrate

Création d'un jeu de données

Nous allons créer quelques fixtures pour peupler notre table et avoir quelque chose à se mettre sous la dent. Pour cela, on crée (ou modifie) un fichier test/fixtures/contacts.yml contenant les deux entrées :

 yaml
John:
  name:    John Doe 
  email:   john@doe.com
  address: 12, rue des champs
  zip:     75009
  city:    Paris
  country: France

Bob:
  name:    Bob Doe 
  email:   bob@doe.com
  address: 1, place du pré 
  zip:     35000
  city:    Rennes
  country: France

On insère les données dans la base :

$ rake db:fixtures:load

Ces données permettront par la suite de tester plus facilement l'application.

Scaffolding

On crée un module basique de gestion de nos contacts :

$ ruby script/generate scaffold Contact

Faites pointer votre navigateur sur http://0.0.0.0:3000/contacts pour tester les scripts générés automatiquement.

Scaffolding basique dans rails 1.2.2

Ce n'est effectivement pas très beau, vous avez raison, mais c'est déjà fonctionnel... et surtout, cela ne nous a pas pris plus de 5 minutes !

À suivre

On ne s'arrêtera pas en si bon chemin, le prochain volet de ce tutoriel fera notamment évoluer notre schéma de base de données... stay tuned !

samedi 25 mars 2006

FreeOnRails, un hébergement gratuit pour vos applications Rails

[via Scoopeo]

Je vous avais fait une fausse joie récemment en annonçant que free.fr allait proposer gratuitement Ruby on Rails sur les pages perso. Hélas, fausse alerte, et jusqu'à aujourd'hui, impossible de trouver un hébergeur gratuit proposant Ruby et son framework superstar...

Jusqu'à ce que FreeOnRails ouvre ses portes ;)

Seules conditions :

  • Posséder un nom de domaine dédié,
  • S'inscrire et poster une demande d'hébergement motivée sur le forum ad-hoc.

Les caractéristiques de l'hébergement proposé sont très interessantes :

  • Pas de pub,
  • 100 Mo d'espace,
  • 1 Go de bande passante mensuelle,
  • Un accès SSH,
  • FastCGI,
  • PHP5 & Perl (au cas où ?),
  • Bases MySQL 4.1.x illimitées,
  • Sous-domaines, comptes ftp et emails illimités.

vendredi 17 février 2006

Ruby on Rails sur les pages perso de Free

Il semblerait que Free se prépare à proposer Ruby on Rails sur leur service d'hébergement de pages personnelles... Si c'est avéré, ça sera un formidable tremplin pour ce framework efficace et pour le langage Ruby, réellement très attachant :)

Edit : Fake. Déçu !

vendredi 20 janvier 2006

Apprendre Ruby on Rails facilement

[ Via Typhon weblog ]

J'ai entre les mains l'un des petits derniers des éditions Eyrolles - décidemment très productifs ces temps-ci - Ruby on Rails. C'est la traduction française du fort réputé Agile Web Development with Rails initialement écrit par Dave Thomas et David Heinemeier Hansson (ni plus ni moins que l'auteur du framework).

Le livre est une mine d'informations illustrée d'exemples pratiques notamment par le biais de la réalisation d'une boutique en ligne en très peu de temps et d'opérations. L'ouvrage est clair, accessible, exhaustif et bourré d'humour. On y trouve une des meilleures introduction au design pattern MVC que j'ai pu lire, une reflexion pertinente sur les méthodologies de développement ainsi qu'un référentiel complet des fonctions usuelles Ruby/Rails.

Cerise sur le gâteau, un partenariat avec l'hébergeur Typhon a été établi afin de proposer une réduction de 50% sur leur offre d'hégergement Découverte Rails pour tout acheteur du livre.

Si vous vous interessez de près ou de loin à Ruby et plus particulièrement à Rails, vous pouvez acheter l'ouvrage les yeux fermés :-)

dimanche 8 janvier 2006

Interlude - Installer un blog Typo

En attendant le tutorial complet de la création d'une application avec Ruby on Rails et RadRails, voila de quoi patienter et découvrir un peu plus les possibilités du framework.

Les applications RoR fleurissent un peu partout ces temps-ci, et certaines sont assez bluffantes. Je viens de tomber sur Typo, un gestionnaire de Weblog très sympa écrit en Ruby et doté de fonctionnalités tout à fait interessantes :

  • Interface tout AJAX,
  • Notification de commentaires et trackback par mail et messagerie jabber,
  • Pings automatiques vers des sites comme Technorati,
  • Gestion de tags (multicatégories, ou folksonomies),
  • Gestionnaire de pages statiques,
  • Contrôle du SPAM avancé (blacklistes locales et distantes, nombre d'URL dans un commentaire, etc.),
  • Gestion intelligente du cache des pages,
  • Nombreux plugins vers des sites disposant d'API (FlickR, Del.icio.us, Upcomming, LastFM, etc.)
  • Etc.

Bon, le plus simple pour se rendre compte de l'interêt de cet outil, c'est de l'installer et de le tester soi-même.

Tout d'abord, et après avoir installé RoR sur Ubuntu, il faut récupérer les sources Subversion [1] de Typo :

$ cd /path/to/docroot
$ svn checkout svn://leetsoft.com/typo/trunk typo

Ceci fait, il faut créer une base de données MySQL dédiée à Typo :

$ cd typo
$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12 to server version: 4.1.12-Debian_1ubuntu3.1-log

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> CREATE DATABASE typo_dev;
Query OK, 1 row affected (0.00 sec)

mysql> \q;

On va y insérer le schema SQL fourni :

$ mysql -u root -p typo_dev < db/schema.mysql.sql

Il nous reste à configurer le fameux fichier ./config/database.yml :

login: &login
  adapter: mysql
  host: localhost
  username: <nom_utilisateur_mysql>
  password: <votre_mot_de_passe>

On lance Webrick, le petit serveur web fourni avec RoR :

$ script/server

Et on teste on faisant pointer son navigateur à l'adresse 0.0.0.0:3000.

Bon amusement :)

Notes

[1] Si vous ne disposez pas de Subversion, sudo apt-get install subversion

vendredi 6 janvier 2006

Ruby on Rails #1 - Lets go Ruby !

Je découvre Ruby on Rails (RoR pour les intimes), c'est assez sympa. Pour mémoire, c'est un framework de developpement web rapide basé sur le motif de conception MVC qui offre une facilité de conception, de déploiement ainsi qu'une maintenance aisée, le tout en langage Ruby. J'en veux pour preuve ces quelques vidéos qui m'ont laissées pour le moins scié en quatre, notamment celle-ci.

En plus, ça tourne chez Typhon, mon hébergeur préféré :)

Ce billet est donc le premier d'une série que je rédigerai au gré de mes découvertes de cet outil qui promet d'être passionnant. Commençons par le commencement, l'installation de l'environnement.

Lire la suite...