Ruby on rails

De wiki jackbot
Aller à la navigation Aller à la recherche

Ruby on rails est un framework web libre écrit en Ruby. Il est basé sur l'architecture Modèle-Vue-Contrôleur (MVC). Il a pour but de respecter deux principes fondamentaux de la programmation

  • DRY : Don't repeat yourself, ne vous répétez pas
  • Convention Over Configuration, Convention plutôt que configuration

Les générateurs

Ruby on Rails vient avec bon nombres de scripts appelé des générateurs, qui on pour but d'aider au développement en créant les fondations d'une nouvelle application Rails.

$ rails new blog

Va ainsi crée toute une arborescence :

$ tree -d -L 2
.
└── blog
    ├── app
    ├── bin
    ├── config
    ├── db
    ├── lib
    ├── log
    ├── node_modules
    ├── public
    ├── storage
    ├── test
    ├── tmp
    └── vendor
  • app contient les models, views, helpers, mailers, channels, jobs, et assets pour l'application.
  • bin contient les scripts permettant démarrer de l'application, ainsi que d'autres script pour définir, mettre à jour, déployer ou exécuter l'application.
  • config contient la configuration des routes, bases de données et autres.
  • db contient sans surprise la base de données, ainsi que les migrations.
  • lib contient les modules pour l'application.
  • log contient simplement les logs.
  • public contient des fichiers statiques ainsi que des ressources compilées. Quand l'application est lancée, ce dossier est exposé tel quel.
  • storage stockage actif de fichier.
  • test contient les tests unitaires
  • tmp contient des fichiers temporaires
  • vendor contient des gems externe

On y trouve également les fichiers suivant :

  • Gemfile qui permet de spécifier les dépendances
  • package.json qui permet de spécifier les dépendances vis à vis de npm

Test du serveur

Le coté pratique de RoR est que juste après avoir utilisé un générateur il est possible de démarrer le serveur avec la commande :

$ rails server

Vous pourrez voir le résultat à l'adresse http://localhost:3000 Il s'agit simplement d'une page visant à prouver que le serveur est lancé et RoR est opérationnel.

Notions MVC

L'architecture MVC (Modèle Vue Contrôleur), permet de cloisonner correctement les différentes tâches.

Modèles

Les modèles sont des classes écrite en Ruby utilisées pour représenter les données et possiblement interagir avec la base de données au travers de : "Active Record"

Pour créer un modèle la commande est la suivante :

$ rails generate model Article title:string body:text
Running via Spring preloader in process 21517
      invoke  active_record
      create    db/migrate/20211105132513_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml

Vous pouvez voir que cette commande à créé de nombreux fichiers

  • 20211105132513_create_articles.rb qui contient les modifications à apporter à la base de données
  • article.rb qui est le fichier contenant la classe en Ruby
  • article_test.rb les tests unitaires pour la classe
  • articles.yml (rôle inconnu ... pour l'instant)

La commande précédente se contente de créer les différents fichiers, mais sans modifier la base de données. Pour cela il faut exécuter la commande :

$ rails db:migrate
== 20211105132513 CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.0020s
== 20211105132513 CreateArticles: migrated (0.0020s) ==========================

C'est ici que vont commencer à rentrer en jeu les conventions, car comme vous pouvez le voir, la table se nomme : "articles", donc en minuscule et au pluriel.

Conventions :

  • La convention de nommage sur les modèles est d'écrire tout attaché mais avec une majuscule pour la première lettre de chaque mot : "Table", "NouvelleTable"
  • Le nom des tables dans la base de données sera toujours en minuscule, les mots séparé par des '_' et au pluriel. Exemple : "tables", "nouvelle_tables"

Exemple :

$ rails generate model ArticleTest title:string body:text
Running via Spring preloader in process 8929
      invoke  active_record
      create    db/migrate/20211106075639_create_article_tests.rb
      create    app/models/article_test.rb
      invoke    test_unit
      create      test/models/article_test_test.rb
      create      test/fixtures/article_tests.yml

$ rails db:migrate
== 20211106075639 CreateArticleTests: migrating ===============================
-- create_table(:article_tests)
   -> 0.0022s
== 20211106075639 CreateArticleTests: migrated (0.0023s) ======================

On peut voir ici qu'en nommant un modèle "ArticleTest", donc en respectant la convention d'écrire tout attaché, mais avec une majuscule au début de chaque mot. Rails va être capable de créer la table : "article_tests" donc tout en minuscule, les mots séparés par '_' et au pluriel.

Contenu minimal

Pour fonctionner correctement un modèle doit hériter d'une classe particulière : "ApplicationRecord"

 class NomDuModele < ApplicationRecord
 end

Jouer avec les modèles

Il est tout à fait possible de tester les modèles crées sans modifier l'application, pour ce faire il faut utiliser la console rails avec la commande :

$ rails console

Pour créer un nouvel article, mais sans pour autant le sauvegarder dans la base de données il faut utiliser la méthode "new" :

article = Article.new(title: "Bonjour Rails", body: "Je suis sur rails!")

À cette étape, seule la variable "article" contient des données, l'appel des méthodes "Article.find(1)", "Article.all", ne donnera rien car le modèle Article n'a pas encore interagit avec la base de données.

> article
 => #<Article id: nil, title: "Bonjour Rails", body: "Je suis sur rails!", created_at: nil, updated_at: nil> 

> Article.find(1)
  Article Load (0.2ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):8
ActiveRecord::RecordNotFound (Couldn't find Article with 'id'=1)

Pour modifier la base de données et inclure les informations de la variable "article" il faut utiliser la commande :

> article.save
  TRANSACTION (0.1ms)  begin transaction
  Article Create (0.5ms)  INSERT INTO "articles" ("title", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "Bonjour Rails"], ["body", "Je suis sur rails!"], ["created_at", "2021-11-06 09:23:32.737847"], ["updated_at", "2021-11-06 09:23:32.737847"]]
  TRANSACTION (4.5ms)  commit transaction
 => true 

On peut voir apparaître avec cette commande : " INSERT INTO "articles" ", la base de données a donc bien été modifiée. Maintenant la commande :

> Article.find(1)
  Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<Article id: 1, title: "Bonjour Rails", body: "Je suis sur rails!", created_at: "2021-11-06 09:23:32.737847000 +0000", updated_at: "2021-11-06 09:23:32.737847000 +0000"> 

Renvoie bien des données.

Contrôleurs

Au vu de l'acronyme MVC, après les modèles on serait tenté de continuer avec les vues, cependant l'élément qui va permettre de chercher et d'afficher la vue est le contrôleur. Mais avant d'attaquer ce morceau, il va falloir faire un détour par les routes.

Les routes

Le rôles des routes est de reconnaître les URLs et de déclencher le contrôleur adéquat. Le fichier à modifier est : "config/routes.rb". La syntaxe à utiliser est la suivante :

Verbe_HTTP 'URL', to: 'contrôleur#méthode'

  • Verbe_HTTP, est la méthode avec laquelle la requête sera effectuée : get, post, patch, delete et root.
  • URL, est simplement l'adresse qui doit déclencher le contrôleur
  • contrôleur, correspond au nom du fichier dans le dossier "app/controllers/
  • méthode, les contrôleurs étant des classes écrite en Ruby, elles possèdent des méthodes

Il est important de bien comprendre que les routes seront lues dans l'ordre et que la première qui correspondra sera suivit.

Les verbes HTTP

  • get est simplement le passage par l'URL, historiquement limité à 255 caractères
  • post est utilisé pour envoyer des données au serveur
  • Patch est utilisé pour faire des mises à jours sur les données
  • delete pour effacer des données
  • root est un peu particulier car il s'agit simplement de demander la page par défaut

Les URLs

Pour ce paramètre il peut s'agir tout simplement de l'adresse (toujours par rapport à la racine du site), on peut donc avoir des URLs de ce type: 'aide', ou '/aide'. Cette route sera donc utilisée lorsque le client demande la page : "http://site.domaine/aide"

Mais il peut également s'agir de couple : adresse + paramètre, qu'il faut alors noté de la manière suivante : 'aide/:id', on peut même avoir à faire à des syntaxe du type : 'aide/:id/edit'

Comme écrit précédemment, l'ordre des routes compte ! Vous comprenez donc qu'il est nécessaire que les routes sans paramètres soient écrite avant les routes avec paramètres. Dans le cas contraire si on possède deux routes : 'aide/:id' et 'aide/nouvelle', écrite dans cet ordre dans le fichier, alors il est possible que lors de la consultation de la page "http://site.domaine/aide/nouvelle", le contrôleur utilisé sera celui associé à l'adresse 'aide/:id' et le paramètre "id" prendra la valeur "nouvelle"

en ce qui concerne root, vu qu'il s'agit de la racine du site on omet l'url :

 root to: 'pages#home'

Contrôleurs et méthodes

Pour mieux comprendre les fichiers essentiels aux contrôleurs on va utiliser le générateur inclus dans rails :

rails generate controller ControleurDeTest
Running via Spring preloader in process 22342
      create  app/controllers/controleur_de_test_controller.rb
      invoke  erb
      create    app/views/controleur_de_test
      invoke  test_unit
      create    test/controllers/controleur_de_test_controller_test.rb
      invoke  helper
      create    app/helpers/controleur_de_test_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/controleur_de_test.scss

On peut voir ici les mêmes conventions que pour les modèles, en écrivant "ControleurDeTest", rails va créer le fichier : "controleur_de_test_controller.rb", il est à noter que tous les contrôleurs auront le suffixe "controller"

Tout comme les modèles les contrôleurs sont des classes écrites en Ruby et doivent hériter d'une classe particulière : "ActionController::Base"

 class PagesController < ActionController::Base

def home end

 end

Le fait de déclarer "def home", va forcer le contrôleur à appeler le fichier : "app/views/pages/home.html.erb"

Les vues

Avant d'attaquer les vues, récapitulons dans l'ordre les différentes étapes. Lorsqu'un client demande une URL au serveur il va :

  • consulter les routes
  • appeler la méthode du contrôleur définit dans la route
  • chercher la vue définie dans le contrôleur et possiblement utiliser un modèle pour interagir avec la base de données
  • afficher le résultat

Attardons nous un peu sur la dernière étape, afficher le résultat. Comme vous avez pu le constater le fichier que va chercher le contrôleur n'est pas un fichier html, mais un fichier html.erb. En d'autres termes, ce fichier sera interprété pour générer le code HTML final. Ce format de fichier peut à la fois contenir du code HTML, mais également du code eRuby (Embedded Ruby), qui devra nécessairement se trouver entre des balises spéciales.

Balises <% %>

Cette balise va simplement permettre d'évaluer le code Ruby qui y est écrit, sans rien afficher. Exemple :

Si par exemple on écrit dans le fichier home.html.erb :

 <% @variable_test = "un petit test" %>

Rien ne sera afficher, la seule chose qui sera faite sera d'attribuer la valeur "un petit test" à la variable : variable_test.


Dans le cas où le code nécessite plusieurs lignes, comme le cas des boucles par exemple, il faut alors terminer le code par : <% end %>, exemple :

  <% 3.times do %>
    <li>liste</li>
  <% end %>

Le code HTML généré sera :

  <li>liste</li>
  <li>liste</li>
  <li>liste</li>

Balises <%= %>

Cette balise permet d'afficher ce que retourne le code Ruby écrit à l'intérieur. Reprenons notre exemple d'avant :

 <% @variable_test = "un petit test" %>

Ici on attribut une valeur à la variable test, mais rien n'est affiché, si par contre on écrit :

 <% @variable_test = "un petit test" %>
 <%= @variable_test %>

Le code HTML généré sera :

 un petit test

MVC en action

Maintenant qu'on a vu le rôle et l'utilisation de chaque élément, on va pouvoir construire un exemple qui utilisera toutes ces choses. Dans la section jouons avec les modèles nous avons crée un article dont le titre est : "Bonjour Rails" et dont le contenu est : "Je suis sur rails!". On va faire en sorte d'être capable d'afficher les articles via une URL de ce type : http://site.domaine/article/numéro

Si vous avez bien suivit la première chose à faire est de créer une route.

Créer la route

Il faut donc modifier le fichier : config/routes.rb et y ajouter :

 get 'article/:id' to: 'article#affichage'

dont le rôle sera de réagir à l'URL et d'aller déclencher la méthode "affichage" du contrôleur "article".

Le contrôleur

Créons maintenant le fichier : app/contrôleurs/article_controller.rb, avec le contenu :

 class ArticleController < ActionController::Base

def affichage @article = Article.find(params[:id]) end

 end