Framework de Programmation des Serveurs Web

Initiation à Ruby on Rails (RoR)

Olivier Dalle (@unice.fr)

Université de Nice Sophia Antipolis

Connexion (sign_in)/Deconnexion(sign_out)


Plusieurs modèles de connexion possibles:

  1. Deconnexion automatique quand on ferme le navigateur

Connexion (sign_in)/Deconnexion(sign_out)


Plusieurs modèles de connexion possibles:

  1. Deconnexion automatique quand on ferme le navigateur
  2. Coche optionnelle remember me

Connexion (sign_in)/Deconnexion(sign_out)


Plusieurs modèles de connexion possibles:

  1. Deconnexion automatique quand on ferme le navigateur
  2. Coche optionnelle remember me
  3. Connexion persistente jusqu’à deconnexion manuelle

Connexion (sign_in)/Deconnexion(sign_out)


Plusieurs modèles de connexion possibles:

  1. Deconnexion automatique quand on ferme le navigateur
  2. Coche optionnelle remember me
  3. Connexion persistente jusqu’à deconnexion manuelle

Nous allons choisir cette dernière solution, et implémenter la notion de session.

Session


Le contrôleur de session


Connexion et deconnexion sont des événements…

Le contrôleur de session


Connexion et deconnexion sont des événements traités comme des action REST…

Le contrôleur de session


Connexion et deconnexion sont des événements traités comme des action REST par le contrôleur de session.

Le contrôleur de session


Connexion et deconnexion sont des événements traités comme des action REST par le contrôleur de session.

On commence par faire une nouvelle branche git:

 $ git checkout -b sign-in-out

Le contrôleur de session


Connexion et deconnexion sont des événements traités comme des action REST par le contrôleur de session.

On commence par faire une nouvelle branche git:

 $ git checkout -b sign-in-out

Puis on crée le contrôleur:

$ rails generate controller Sessions --no-test-framework
$ rails generate integration_test authentication_pages

La page de connexion

La page de connexion


Sera accessible par l’URI obtenue avec signin_path

Test pour la création et vue de session


Dans spec/requests/authentication_pages_spec.rb

Test pour la création et vue de session


Dans spec/requests/authentication_pages_spec.rb

Test pour la création et vue de session


Dans spec/requests/authentication_pages_spec.rb

Et bien-sûr le test doit échouer:

$ bundle exec rspec spec/

Définition des routes pour la session


On combine des routes classiques avec des routes sur mesure:
(config/routes.rb)

Définition des routes pour la session


On combine des routes classiques avec des routes sur mesure:
(config/routes.rb)

Définition des routes pour la session


On combine des routes classiques avec des routes sur mesure:
(config/routes.rb)

(via: :delete indique que l’on utilise la requête HTTP DELETE au lieu de GET)

Définition des routes pour la session


Le résultat:

Définition des routes pour la session


Récapitulatif:

Ajout de l’action new initiale


Dans app/controllers/sessions_controller.rb:

Ajout de l’action new initiale


Dans app/views/sessions/new.html.erb

Tests de connexion

Test de connexion invalide


On veut identifier un éventuel message d’erreur…

Test de connexion invalide


On veut identifier un éventuel message d’erreur, on utilise un sélecteur qui désigne le code html suivant:
<div class="alert alert-error">Invalid...</div>

Test de connexion invalide


On veut identifier un éventuel message d’erreur, on utilise un sélecteur qui désigne le code html suivant:
<div class="alert alert-error">Invalid...</div>

Test de connexion invalide


La page de connexion réussie

Le test de la connexion réussie

Le formulaire de connexion


On utilise form_for. Mais situation est de l’enregistrement car nous n’avons pas de modèle pour la session, seulement un contrôleur.

L’équivalent de cette instruction pour la session ne marche pas:

Le formulaire de connexion


On utilise form_for. Mais situation différente de l’enregistrement car nous n’avons pas de modèle pour la session, seulement un contrôleur.

On doit fournir plus d’infos:

Le formulaire de connexion

Analyse du formulaire


On commence par le cas des données invalides.

Analyse du formulaire


On commence par le cas des données invalides.

En cas de données invalide, on affiche a nouveau le formulaire de connexion.

Analyse du formulaire


On commence par le cas des données invalides.

En cas de données invalide, on affiche a nouveau le formulaire de connexion.

Résultat:

Récuperation des données du formmualire


Les infos de débug révèlent:

Récuperation des données du formmualire


Les infos de débug lors de la soumissison révèlent:

Récuperation des données du formmualire


La variable params contient un hash imbriqué:

params[:session] est un hash:

{ password: "", email: "" }

Récuperation des données du formmualire


La variable params contient un hash imbriqué:

params[:session] est un hash:

Récuperation des données du formmualire


Le squelette de l’action create évoluée:

Message d’erreur en cas de connexion invalide

Message d’erreur en cas de connexion invalide

Bug!


Le message d’erreur s’affiche trop longtemps

Bug!


Avant de corriger, on fait un test qui detecte ce bug:

Correction du bug


On utilise flash.now

Cas de la connexion réussie


Persistence de la session


On va ajouter une coche ‘se souvenir de la connexion’

Persistence de la session


On va ajouter une coche ‘se souvenir de la connexion’

On a besoin d’un peu d’aide: (app/controllers/application_controller.rb)

Persistence de la session


On va ajouter une coche ‘se souvenir de la connexion’

Il faut modifier le modèle des utilisateur pour mémoriser le cookie:

Persistence de la session


On va ajouter une coche ‘se souvenir de la connexion’

Il faut modifier le modèle des utilisateur pour mémoriser le cookie.

Comme ca on peut faire la recherche par cookie:

User.find(session[:remember_token])

Persistence de la session


On commence par les tests…

Persistence de la session


On commence par les tests…

Persistence de la session


On commence par les tests puis on modifie le code…

Persistence de la session


On commence par les tests puis on modifie le code (et le schéma) à l’aide d’une migration:

$ rails generate migration add_remember_token_to_users

Persistence de la session


On commence par les tests puis on modifie le code (et le schéma) à l’aide d’une migration:

$ rails generate migration add_remember_token_to_users

Et on écrit le code de la migration:

Persistence de la session


On commence par les tests puis on modifie le code (et le schéma) à l’aide d’une migration:

$ rails generate migration add_remember_token_to_users

Et on écrit le code de la migration.

Puis:

$ bundle exec rake db:migrate
$ bundle exec rake db:test:prepare

Quel cookie utiliser?


Plein de choix possibles:

Quel cookie utiliser?


Plein de choix possibles:

On utilise SecureRandom.urlsafe_base64 qui retourne une chaine de 16 caractères.

Quel cookie utiliser?


Avant de coder, on ajoute le test: (spec/models/user_spec.rb)

Création du cookie


Création d’une méthode privée:

Création du cookie


Création d’une méthode privée:

Création du cookie


Mise en place par une call-back:

Création du cookie


La création effective du cookie se fait dans la méthode sign_in du helper app/helpers/sessions_helper.rb

Création du cookie


La création effective du cookie se fait dans la méthode sign_in du helper app/helpers/sessions_helper.rb

On peut le rendre persistent pour 20 ans!

cookies[:remember_token] = { value:   user.remember_token,
              expires: 20.years.from_now.utc }

Création du cookie


La création effective du cookie se fait dans la méthode sign_in du helper app/helpers/sessions_helper.rb

Tellement fréquent qu’il existe un méthode Rails prédéfinie:

cookies.permanent[:remember_token] = user.remember_token

L’utilisateur courant


Défini par la 2e ligne de la méthode sign_in:

self.current_user = user

L’utilisateur courant


Défini par la 2e ligne de la méthode sign_in:

self.current_user = user

Devient accessible à la fois dans le contrôleur et dans la vue.

L’utilisateur courant


Défini par la 2e ligne de la méthode sign_in:

self.current_user = user

Devient accessible à la fois dans le contrôleur et dans la vue.

A condition de définir l’opérateur d’affectation!

Modification des liens affichés selon l’utilisateur


On Souhaite changer l’affichage selon que l’utilisateur est connecté ou non.

Modification des liens affichés selon l’utilisateur


On Souhaite changer l’affichage selon que l’utilisateur est connecté ou non.

Ajout d’une novelle méthode dans le helper:
app/helpers/sessions_helper.rb

Modification des liens affichés selon l’utilisateur