Ici et ailleurs

Le blog d’un joueur … mais pas que le blog de Sky.

Ruby on Rails : Conventions, mappage basique et migrations

Dans cet article, nous allons enfin rentrer dans le vif du sujet et afin que tout soit clair et que le fonctionnement de Rails ne vous semble pas obscur, nous allons commencer par créer une partie sans utiliser l’outil de scaffolding de Rails, cet outil qui nous permettra plus tard d’économiser un temps précieux. Pour commencer, nous allons parler un peu des conventions de nommage de RoR puisqu’une grande partie de la magie Rails se situe à ce niveau.

Conventions de nommage Rails

Je suis tombé sur ce site qui résume bien la situation. Gardez bien ces conventions dans votre tête.

Ce qui suit est extrêmement important et reprend le point “Convention Over Configuration” sur lequel s’appui le framework Rails.

Dans la base de données

Le nom des tables est toujours au pluriel et en minuscules, si le nom comporte plusieurs mots, ils sont séparés par des underscores.

ex: former_users, users

Les clés primaires doivent être nommées “id”.

Les clés étrangères doivent être nommées avec le nom singulier de la table cible suffixé de “_id”.

ex: pour une table rights, la clé étrangère dans la table users donnera right_id

Modèle

Le nom du modèle est toujours le singulier de la table se trouvant dans la base de données. Il respecte la notation CamelCase et le fichier est situé dans le répertoire /app/models/.

ex. classes: FormerUser, User
ex. fichiers: /app/models/former_user.rb, /app/models/user.rb

Contrôleur

Le contrôleur est toujours au pluriel et en CamelCase. Il est suffixé du mot “Controller” et est sauvegardé dans le dossier /app/controllers/.

ex. classes: FormerUsersController, UsersController
ex.fichiers: /app/controllers/former_users_controller.rb, /app/controllers/users_controller.rb

Certains autres fichiers dépendent du contrôleur, c’est le cas des helpers (ex: UsersHelper dans /app/helpers/users_helper.rb), des layouts et des vues dont nous allons parlé.

Vue

Les vues sont donc déclarées dans des fichiers situés dans /app/views/nom_du_controleur/. Les layouts, dont on parlera plus tard dans /app/views/layouts/.

ex : /app/views/users/list.html.erb

Maintenant que nous sommes au clair là dessus, nous allons faire des choses plus intéressantes. Je vais essayé d’avancer au fur et à mesure pour expliquer pas à pas comment opère Rails. Nous allons volontairement commencer par créer la vue. Une vue oui, mais pour quel contrôleur ?

Ce que nous allons créer

Pas grand chose de très utile, cet article est là avant tout pour expliqué les mécanismes de routage de Rails à travers un semblant de gestion de notes. Dans ce premier article, nous allons créer la page qui permet l’affichage des notes.
Commençons donc par créer une page avec juste un message dans le dossier /app/views/notes/ et nommons là index.html.erb.

<!DOCTYPE html>
<html>
<head>
  <title>Notes : Liste des notes</title>
</head>
<body>

<h1>Liste des notes</h1>

</body>
</html>

Le but est donc de pouvoir accéder à cette page avec l’URL http://localhost:3000/notes.

Affichons cette page!

N’oubliez pas de lancer le serveur web grâce à la commande rails server via la console Windows en étant dans le dossier de votre application.

Un peu de routage

Lorsque vous tentez d’accéder à l’URL du dessus, la requête HTTP ressemble à

GET /notes

En recevant cette requête, Rails va essayer de la “mapper” à un contrôleur en regardant dans l’un des fichiers les plus important, le fichier /config/routes.rb. Ouvrons le. De base, juste une multitude de commentaires pour nous expliquer comment commencer. Nous allons faire simple et rajouter une route pour que notre URL fonctionne :

match 'notes' => 'notes#index'

On fait donc correspondre la requête GET /notes à l’action index du contrôleur notes. Essayer dans votre navigateur et vous obtenez l’erreur “uninitialized constant NotesController”. En effet, notre contrôleur n’existe pas encore, nous allons donc le créer.

Un contrôleur sinon rien

Direction le dossier /app/controller/ pour créer le fichier notes_controller.rb. Éditons le !

class NotesController < ActionController::Base
end

Nous faisons hériter notre contrôleur d’une classe de base qui va mettre en place la magie Rails et nous ne définissons aucune méthode. Accédez une nouvelle fois à http://localhost:3000/notes, et voilà le travail !

Ce comportement peut sembler obscur et c’est pourquoi je vais essayer d’expliquer un peu ce qui se passe “behind the scene”.

Une histoire de conventions

Je l’ai déjà dit plusieurs fois, Rails possède de base des comportements par défaut qui permettent de gagner un temps fou, encore faut-il les comprendre. On a dit que Rails se base sur le modèle d’architecture REST et qu’on manipule des ressources, dans notre cas, notre ressource est notes. Les requêtes HTTP fournissent toutes les opérations nécessaires pour manipuler cette ressource. Toutes ces requêtes possèdent un équivalent en terme d’actions (de méthodes) Rails. Un petit tableau dans le cas de notre ressources notes pour mieux comprendre.

verbe HTTP chemin action fonction
GET /notes index affiche la liste de toutes les notes
GET /notes/new new affiche un formulaire pour la création d’une nouvelle note
POST /notes create crée une nouvelle note
GET /notes/:id show affiche une note spécifique
GET /notes/:id/edit edit affiche un formulaire pour la modification d’une note
PUT /notes/:id update met à jour une note
DELETE /notes/:id destroy supprime une note

Chaque action possède appelle par défaut la vue qui lui est associée. Par exemple, l’action show appelle la vue /app/views/notes/show.html.erb.

A ce moment, vous vous dites sûrement que d’écrire à chaque fois les règles de routage pour chaque action serait fastidieux. On aurait quelque chose du genre:

match 'notes' => 'notes#index'
match 'notes/:id' => 'notes#show'
match 'notes/new' => 'notes#new'
...

Et c’est là que Rails introduit le mot clé magique resources, ainsi écrire (toujours dans /config/routes.rb):

resources :notes

permet de créer les 7 routes ci-dessus toutes reliées au contrôleur notes.

Alors prenons un exemple simple que nous réaliserons plus tard: l’ajout d’une note, c’est à dire la méthode new. Lorsque vous tapez dans votre navigateur http://localhost:3000/notes/new, Rails cherche une correspondance dans le fichier /config/routes.rb et tombe sur notre règle resources :notes, il appelle donc automatiquement la méthode new du contrôleur notes qui par défaut va afficher la vue /app/views/notes/new.html.erb. Tout ça reste transparent pour l’utilisateur.

La persistance de nos données

Pour sauvegarder nos notes, il nous faut bien évidemment une base de données et donc un modèle.

Notre modèle

Vous allez voir, rien de plus simple. Commençons par créer le fichier note.rb dans le répertoire /app/models/ et éditons le comme suit :

class Note < ActiveRecord::Base
end

En faisant hériter notre classe de la classe ActiveRecord, on dispose automatiquement des opérations CRUD (Create, Read, Update, Destroy) ainsi que d’un tas d’autres méthodes pour manipuler nos données. Le modèle est automatiquement conscient des champs de notre table.

En parlant des données, notre table n’est pas encore créée, remédions à ça ! Et pour ce faire, plusieurs méthodes:

  • manuellement: on crée notre table via, dans mon cas, MySQL Workbench,
  • grâce aux migrations de Rails: un fichier ruby qui décrit les opérations SQL à effectuer en nous donnant la possibilité de revenir en arrière, c’est cette méthode que nous allons utiliser.

Les migrations

Nous n’avons pas besoin de tonnes d’informations pour nos notes, uniquement un champ description et un champ created_at.

Une migration est une classe qui définit deux méthodes: self.up et self.down, respectivement pour effectuer et annuler les actions effectuées. On peut écrire une migration pour modifier le schéma d’une base de données mais aussi pour rajouter des champs, des valeurs.

Nous allons donc écrire notre migration. Mais avant ça direction la console Windows, nous allons générer un squelette de migration grâce à la commande:

rails generate migration CreateNote

Cette commande doit être exécutée dans le dossier de votre application, naviguez à coup de cd jusqu’à votre dossier, dans mon cas c:\Ruby192\Code\japprends

Un fichier a donc été créé dans /db/migrate/, éditons-le.

class CreateNote < ActiveRecord::Migration
  def self.up
	# On crée notre table
	create_table :notes do |t|
		t.text :description
		t.timestamps
	end
	# On rajoute deux valeurs pour nos tests
	Note.create :description => "Ma premiere note"
	Note.create :description => "Ma deuxieme note!"
  end

  def self.down
	drop_table :notes
  end
end

Active Record met à notre disposition des méthodes qui permettent d’altérer notre base de données comme create_table (la liste ici) dont on se sert ici. On crée donc notre table, nos colonnes et on ajoute deux champs de test. Il nous reste ensuite à exécuter notre migration, toujours dans la console, tapez:

rake db:migrate

La commande rake db:rollback permet d’annuler la dernière migration en appelant la méthode self.down de cette dernière.

On avait déjà parlé de rake qui met à notre disposition quelques scripts très pratique. Cette commande crée donc notre table et les champs suivants:

  • id de type int
  • description de type text
  • created_at et updated_at de type datetime

Vous remarquerez que 3 champs ont été rajoutés automatiquement par Active Record: id, created_at et updated_at, ce qui nous arrange plutôt. Notre table est donc créée, nous allons pouvoir continuer.

Si vous souhaitez de plus amples informations sur les migrations, les guides Rails sont très bien réalisés.

Dernières modifications

On a donc dit que le but de cet article était d’afficher les notes présentes en base de données. Nous avons notre contrôleur, notre modèle et notre vue, il ne reste plus qu’à tout mettre en relation, et pour cela, nous allons modifier notre contrôleur et notre vue.

Notre contrôleur

Nous allons rajouter très peu de choses dans notre contrôleur, juste redéfinir la méthode index et lui dire de récupérer toutes les notes grâce au modèle et de les stocker dans une variable d’instance.

class NotesController < ActionController::Base
	def index
		@notes = Note.all # recupère toutes les notes
	end
end

Vous remarquerez que notre modèle appelle automatiquement la vue appropriée si rien n’est précisé puisque c’est le comportement par défaut. Maintenant que notre contrôleur récupère nos notes et les mets à disposition de notre vue grâce à la variable d’instance @notes, nous allons modifier notre vue pour afficher toutes nos notes.

Notre nouvelle vue

Modifions à présent notre vue en effectuant une boucle sur la variable @notes qui est un tableau contenant toutes nos notes et voilà ce que devient notre fichier /app/views/notes/index.html.erb:

<!DOCTYPE html>
<html>
<head>
  <title>Notes : Liste des notes</title>
</head>
<body>

<h1>Liste des notes</h1>
<ul>
<% @notes.each do |note| %>
	<li><em><%= note.created_at.strftime("%m/%d/%Y") %></em> - <%= link_to(note.description, note_path(note.id)) %></li>
<% end %>
</ul>
</body>
</html>

Plusieurs choses à expliquer ici, notamment les balises permettant d’écrire du code ruby dans le code HTML. Il en existe deux types:

  • % qui permet d’exécuter du code ruby, il ne sera pas affiché dans la page, par exemple pour parcourir notre boucle,
  • %= qui permet d’exécuter puis d’afficher le résultat du code ruby, l’équivalent du echo en php.

On utilise ensuite la méthode strftime sur notre date de création pour la formatter comme on le souhaite, au passage, un article présentant une autre solution plus pratique sur le long terme : pour le formattage de dates.

Et pour finir, la partie intéressante. Pour créer un lien sur notre description, on utilise un helper appelé link_to qui prend deux paramètres: le nom du lien et l’URL. On met en nom la description de notre note et en URL, on utilise encore un helper qui nous conduit vers l’action show de notre contrôleur.

D’où sort ce helper ? Rappelez vous la ligne dans /config/routes.rb:

resources :notes

Cette ligne crée automatiquement des helpers pour accéder aux URLs, pour notre ressource notes on a donc:

  • notes_path
  • new_note_path
  • edit_note_path(id)
  • note_path(id)

En remplaçant le suffixe path par url, on obtient le chemin préfixé de l’hôte et du port, c’est donc ce que j’utilise ici.

Le mot de la fin

Et normalement, en accédant à http://localhost:3000/notes, vous devriez obtenir ceci:

Notre première page dynamique avec Rails

Notre première page dynamique avec Rails


Nous voici arriver à la fin de cet article plutôt consistant, j’espère avoir réussi à expliquer une partie de la magie Rails, dans le prochain article, nous parlerons layout et formulaires en passant à la partie création de notes.

Si vous avez des questions ou des points que vous souhaitez voir abordés, n’hésitez pas!

Tags: , , , , , ,

2 commentaires pour “Ruby on Rails : Conventions, mappage basique et migrations”

  1. xandar dit :

    Article très sympa.

    Je n’ai pas tout lu car la techno’ ne m’intéresse pas trop pour le moment (mais j’ai bookmark) cependant le début de ton article rappelle beaucoup la façon de fonctionner de cakePHP (le seul framework que j’ai vu à ce jour).

  2. Ruby | Pearltrees dit :

    [...] Ici et ailleurs » Ruby on Rails : Conventions, mappage basique et migrations [+] Dév home • contact • blog • fb • twitter to experience pearltrees activate javascript. [...]

Laisser un commentaire

Si vous avez un compte sur WeFrag, connectez-vous pour publier un commentaire.

Vous pouvez, entre autres, utiliser les tags XHTML suivant :
<a href="" title="">...</a>,<b>...</b>,<blockquote cite="">...</blockquote>,<code>...</code>,<i>...</i>