JeuWeb - Crée ton jeu par navigateur
[Ruby on Rails] Créer un espace d'administration - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [Ruby on Rails] Créer un espace d'administration (/showthread.php?tid=4399)



[Ruby on Rails] Créer un espace d'administration - Sephi-Chan - 10-10-2009

Créer un espace d'administration

Cet article concerne la version 2.x de Ruby on Rails.

Ruby on Rails propose un système de routes très puissant. Outre la simplicité de mise en place de servie Web REST, ces routes permettent de créer des espaces.

En combinant cela avec les contrôleurs, nous allons voir comment mettre en place un espace d'administration.

Pour se faire, nous admettrons avoir 5 contrôleurs :
  • ApplicationController : le contrôleur frontal de l'application, tout ce qui y est définit est global à l'application.
  • AdministrationController : le contrôleur de la zone administration. Ce contrôleur aura des filtres qui permettront de sécuriser automatiquement notre espace d'administration. Il hérite de ApplicationController et tous les contrôleurs des pages de l'administration héritent de lui.
  • PublicController : le contrôleur de la zone publique. Il hérite de ApplicationController et tous les contrôleurs (en dehors de ceux de l'administration) héritent de lui.
  • UsersController : le contrôleur qui gère les utilisateurs côté publique (c'est ce contrôleur qui contiendra les actions concernant les comptes utilisateurs (lister, afficher, créer, modifier, etc.).
  • UsersController : tout comme le précédent UsersController, à la différence près que celui-ci sera dans la zone administration (nous verrons comment le distinguer de celui de la partie publique).

L'héritage va beaucoup nous servir ici : comme tous les contrôleurs de la partie administration héritent de AdministrationController, il suffit de mettre la restriction d'accès dans celui-ci et ça s'appliquera automatiquement aux sous-classes !

De la même manière, faire un système qui permet de mettre le site en maintenance sera très simple, il suffira de restreindre l'accès au contrôleur PublicController et paf, toute la partie publique sera innaccessible (et vous pourrez bien entendu lever cette exception pour certains contrôleurs particuliers si vous souhaitez qu'ils restent accessible pendant la mainteance) !


Voici l'arboresscence de notre dossier app/ (comme souvent, épuré pour l'exemple).


.
`-- app
|-- controllers
| |-- administration
| | |-- administration_controller.rb
| | |-- users_controller.rb
| |-- application_controller.rb
| |-- public_controller.rb
| `-- users_controller.rb
|-- models
| |-- user.rb
`-- views
|-- administration
| |-- administration
| | `-- index.html.erb
| |-- users
| | |-- new.html.erb
| | |-- show.html.erb
| | |-- edit.html.erb
| | |-- index.html.erb
|-- public
| `-- index.html.erb
|-- layouts
| |-- administration.html.erb
| |-- public.html.erb
| `-- application.html.erb
`-- users
|-- edit.html.erb
|-- index.html.erb
|-- new.html.erb
`-- show.html.erb

On a donc des contrôleurs, qui sont des classes, les contrôleurs ApplicationController, PublicController et UsersController sont placés à la racine du répertoire controllers/, alors que AdministrationController et l'autres UsersController sont placé dans le répertoire controllers/administration/ (que l'on crée nous-même).


Voici le code basique de nos contrôleurs. Les méthodes portent des noms suffisemment explicites, leur implémentation n'a donc pas vraiment d'importance pour cet article.


# application_controller.rb
class ApplicationController < ActionController::Base

# current_user is now accessible in both controllers and views.
helper_method :current_user


protected

# Return the current user.
def current_user
# ...
end

# Require logged in user.
def require_user
# ...
end

# Require logged out user.
def require_no_user
# ...
end

end


# public_controller.rb
class PublicController < ApplicationController

before_filter Confusedhow_maintenance, :if => :website_is_in_maintenance?
layout 'public'


def index
# Used as homepage for the public side of the website.
end


protected

# To set the maintenance mode, just create a file called maintenance.txt in tmp/.
def website_is_in_maintenance?
File.exists?(Rails.root.join('tmp', 'maintenance'))
end

def show_maintenance
render :file => 'views/maintenance.html.erb',
:layout => 'maintenance'
return
end

end


# users_controller.rb
class UsersController < PublicController
# ...
end


# administration/administration_controller.rb
class Administration::AdministrationController < ApplicationController

before_filter :require_authentication
layout 'administration'


def index
# Used as homepage for the administration of the website.
end


protected

def require_authentication
unless current_user && current_user.is_administrator?
render :file => 'views/forbidden.html.erb',
:layout => 'error',
Confusedtatus => 403
return
end
end

end


# administration/users_controller.rb
class Administration::UsersController < Administration::AdministrationController
# ...
end


Comme vous pouvez le voir, les before_filter sont surpuissants ! Avec ça, on sécurise tous les contrôleurs qui étendent le contrôleur sécurisé en une poignée de ligne (si après ça quelqu'un dit que la POO sert à rien… Smile).

Nous avons donc le socle de notre espace administration. Passons maintenant aux routes pour rendre tout ça sympa !

Le but de la manœuvre est d'avoir une application RESTful (là où c'est utile) et de pouvoir distinguer facilement l'espace dans lequel on est. Quelques exemples d'URL que l'on aura.
  • /users/new : la page de création d'un compte.
  • /users/1 : la page qui affiche le profil de l'utilisateur d'ID 1.
  • /users/1.xml : la page qui affiche le profil de l'utilisateur d'ID 1 sous forme de document XML.
  • /users/1.png : une page qui renvoie un document de mime type image/png. Pour par exemple faire une signature dynamique que l'utilisateur d'ID pourra mettre sur les forums !
  • /users/1/edit : la page d'édition du profil de l'utilisateur d'ID 1. Ici, on utilisara généralement un before_filter pour être sur que l'utilisateur 1 est bien le current_user, puisque l'utilisateur connecté peut modifier uniquement son profil.
  • /administrations/users : la page d'administration qui liste tous les utilisateurs.
  • /administration/users/1/edit : la page d'administration qui permet de modifier le profil de l'utilisateur d'ID 1.
  • /administrations/ : la page par défaut de la partie administration. On peut mettre ce qu'on veut.


    Pour mettre ça en place, nous allons modifier le fichier config/routes.rb pour y mettre ce contenu :


    ActionController::Routing::Routes.draw do |map|

    map.root :controller => 'public', :action => 'index'
    map.resources :users

    map.namespace :administration do |administration|
    administration.root :controller => 'administration'
    administration.resources :users
    end

    end


    Et oui, c'est très simple et ça parle tout seul ! Avec root, on définit la racine du namespace global. Ainsi, quand on va sur la page principale du site, c'est l'action index du contrôleur PublicController qui est rendue.

    Ensuite, on définit une ressource users. Par défaut, cette ressource utilisera le contrôleur du même nom : UsersController. C'est ça qui nous permettra d'avoir des URLs cool comme montrées plus haut.

    Puis on définit un namespace, ou espace de nom. Il sera baptisé administration. On y accédera en ajoutant /administration/ à l'adresse du site.
    Dans ce namespace, on définit un contrôleur par défaut et une ressource users, comme on l'a fait pour la partie publique.

    Et c'est tout !

    Cerise sur le gateau, définir ces routes a pour effet de créer une poignée d'aides de vue (view helpers) pour vous. Vous pouvez les voir en tapant un rake routes dans un terminal.
    Ces view helpers vous permettent de générer des URLs.

    Ce tableau est composé de 4 colonnes :
    • La première est le nom de la route. C'est ce nom là que vous pourrez utiliser dans vos vues, en le suffixant de _path ou de _url selon que vous voulez un chemin relatif ou absolu.
    • La seconde, c'est la méthode HTTP pour accéder. On est dans le cadre d'une application REST, la même URL peut pointer sur plusieurs choses selon la méthode HTTP qu'on utilise. Ainsi, envoyer une requête GET sur l'URL /users/1 revient à demander d'afficher l'utilisateur d'ID 1, alors que la même URL avec la méthode DELETE supprime la ressource.
    • La troisième est le modèle de l'URL, ce à quoi ressemblera l'URL dans la barre. On utilise des placeholders pour les identifiants des ressources. Quand on lit :id, ça veut dire que la variable params[:id] sera disponnible dans l'action correspondante. Ça veut aussi dire qu'il faut donner cet identifiant à la route, quand on l'utilise.
    • La quatrième permet affiche le couple contrôleur/action qui sera appelé en se rendant à l'URL indiquée.



    root / {:controller=>"public", :action=>"index"}
    users GET /users(.:format) {:controller=>"users", :action=>"index"}
    POST /users(.:format) {:controller=>"users", :action=>"create"}
    new_user GET /users/new(.:format) {:controller=>"users", :action=>"new"}
    edit_user GET /users/:id/edit(.:format) {:controller=>"users", :action=>"edit"}
    user GET /users/:id(.:format) {:controller=>"users", :action=>"show"}
    PUT /users/:id(.:format) {:controller=>"users", :action=>"update"}
    DELETE /users/:id(.:format) {:controller=>"users", :action=>"destroy"}
    administration_root /administration {:controller=>"administration/administration", :action=>"index"}
    administration_users GET /administration/users(.:format) {:controller=>"administration/users", :action=>"index"}
    POST /administration/users(.:format) {:controller=>"administration/users", :action=>"create"}
    new_administration_user GET /administration/users/new(.:format) {:controller=>"administration/users", :action=>"new"}
    edit_administration_user GET /administration/users/:id/edit(.:format) {:controller=>"administration/users", :action=>"edit"}
    administration_user GET /administration/users/:id(.:format) {:controller=>"administration/users", :action=>"show"}
    PUT /administration/users/:id(.:format) {:controller=>"administration/users", :action=>"update"}
    DELETE /administration/users/:id(.:format) {:controller=>"administration/users", :action=>"destroy"}

    Voici un exemple d'utilisation de ces view helpers :


    <%# views/public/index.html.erb %>
    <ul id="menu">
    <li><%= link_to 'Administration', administration_root_path %></li>
    <% if current_user %>
    <li><%= link_to 'Afficher votre profil', current_user %></li>
    <li><%= link_to 'Modifier votre profil', edit_user_path(current_user) %></li>
    <% else %>
    <li><%= link_to 'Créer un compte', new_user_path %></li>
    <% end %>
    </ul>

    Comme vous pouvez le voir, on utilise le nom donné dans la première colonne, auquel on fait suffixer _path (ou _url, si vous voulez des URLs absolues).
    Si besoin, on donne des arguments. Dans notre cas, si le visiteur est connecté (et qu'il est l'utilisateur d'ID 23), on va afficher un lien vers sa page d'édition.
    En passant un objet User à notre view helper, il va automatiquement savoir qu'on cherche à faire un lien vers cet utilisateur et générer le lien /users/23/edit.
    Pour le lien d'affichage du profil, c'est encore plus magique ! En passant directement notre objet User, Rails va lui-même deviner la route pour afficher cette ressource, grâce à ses conventions.


    Quand quelqu'un tentera d'accéder à la page /administration/ ou /administration/users/index (ou toute autre ressource de l'espace administration), la requête HTTP passera par le côntrôleur AdministrationController qui va alors tester si l'utilisateur a le droit d'être ici et le rejeter si ça n'est pas le cas en rendant une vue qui lui explique et un code HTTP 403 (Forbidden).

    On peut imaginer d'autres comportements, mais la base est là ! Smile


    Comme vous pouvez le voir, la puissance de Ruby on Rails, c'est d'utiliser massivement les conventions de nommage, ce qui permet de se passer de beaucoup de configuration !


    Si ce sujet vous a intéressé — que Ruby vous tente ou non — je vous serais reconnaissant de me donner votre ressenti afin que je puisse l'améliorer.


    Sephi-Chan



RE: [Ruby on Rails] Créer un espace administration - My Hotel - 10-10-2009

Raaaa! Le principe est franchement tentant, c'est super puissant tout ça! Petit à petit, je me rends compte que Ruby est vraiment intéressant, mais j'arrive pas à m'y mettre! Je sais pas pourquoi, mais je coince sur la syntaxe en fait Smile

Bref, merci pour ce bon tuto, ça m'a ouvert les yeux Wink


RE: [Ruby on Rails] Créer un espace administration - Sephi-Chan - 10-10-2009

Si tu as des questions, n'hésite pas à demander par MP. Peut-être arriverais-je à t'éclairer. Et puis, ça peut me donner des idées d'articles. Smile


Sephi-Chan


RE: [Ruby on Rails] Créer un espace d'administration - Enark - 11-10-2009

Salut très bon tutorial, j'ai quelques question à te poser si ça te dérange pas?
D'abord j'aimerais savoir un truc, vu comme ça ça à l'air assez simple RoR mais une fois sur des fonctions plus "complexes" (notamment pour un jeu par navigateur?) n'as-tu pas du mal à trouver ce qu'il te faut?
Secondo encore une fois il parait que Ror consomme pas mal de Ram, y'a t-il un système de cache performant et as-tu déjà fait des stress test? Je suppose que non vu que tu n'as pas encore achevé le développement de ton jeu (très sympa le système de map d'ailleurs!) mais je n'ai pas envie de me lancer dans le développement en Ror pour tout reprendre dans 5-6 mois en php.
Pour finir, les web-services ont l'air vraiment pas mal mais je suppose que ça doit être horriblement long à mettre en place non?
C'est pas trop l'endroit pour poser des questions peut-être mais bon voilà o:
D'avance, merci.


RE: [Ruby on Rails] Créer un espace d'administration - Sephi-Chan - 11-10-2009

(11-10-2009, 10:08 PM)Enark a écrit : Salut très bon tutorial, j'ai quelques question à te poser si ça te dérange pas?
D'abord j'aimerais savoir un truc, vu comme ça ça à l'air assez simple RoR mais une fois sur des fonctions plus "complexes" (notamment pour un jeu par navigateur?) n'as-tu pas du mal à trouver ce qu'il te faut?

Honnêtement, j'ai tout ce qu'il me faut pour un webgame, je dirais même que — contrairement à ce que je pensais au début — RoR est très adapté aux applications complexes comme un jeu. Quand on développe avec, on apprend à simplifier le fonctionnement d'un système, à l'éclater. Et tous les bouts deviennent finalement simple à gérer. RoR ne m'a pour le moment posé aucune barrière, et plus j'en apprends, plus je pense que ça n'arrivera pas.


(11-10-2009, 10:08 PM)Enark a écrit : Secondo encore une fois il parait que Ror consomme pas mal de Ram, y'a t-il un système de cache performant et as-tu déjà fait des stress test? Je suppose que non vu que tu n'as pas encore achevé le développement de ton jeu (très sympa le système de map d'ailleurs!) mais je n'ai pas envie de me lancer dans le développement en Ror pour tout reprendre dans 5-6 mois en php.

Effectivement, je n'ai personnellement pas fait ce genre de test, mais au boulot, on travaille pour de gros groupes (NouvelObs (et TeleObs, l'objet du mois, MediaObs, etc.), l'Express, etc.) qui ont des sites à fort trafic et ça tourne très bien. Ruby on Rails propose beaucoup de fonctionnalité pour mettre en place des caches (à plusieurs niveaux) simplement et proprement.
De plus, on utilise des outils de cache au niveau du serveur Web, tel que Varnish.
On en utilise aussi au niveau de l'accès aux données, par exemple Memcached.

Et puis, en matière de tenue de charge, je pense que Twitter doit être l'un des sites les plus sollicité du Web. L'application est écrite en Rails (et la rumeur en 2008 qui disait que ça allait passer à PHP était fausse), même si ils ont des backends sans doute très robuste écrit avec des langages bien plus performants.


(11-10-2009, 10:08 PM)Enark a écrit : Pour finir, les web-services ont l'air vraiment pas mal mais je suppose que ça doit être horriblement long à mettre en place non?

Au contraire, c'est con comme la lune à créer puisque ça utilise REST. Ça sera le sujet de mon article de demain. Wink


Sephi-Chan, et bienvenue !


RE: [Ruby on Rails] Créer un espace d'administration - Enark - 11-10-2009

Et merci, sympa la réponse rapide et développée ça me change tiens Smile
Bon bah mon cœur balance toujours, j'ai peur de me retrouver bloqué dans ma lancée à cause du manque de ressources disponibles vu que j'apprends en autodidacte (la doc a l'air bien beurk au passage Sad) mais d'un autre côté je suis amoureux de la syntaxe et de la philosophie rails.
D'après toi Rails est bien assez mature pour se lancer dedans, donc je sais pas trop je me tâte encore même si j'avoue que tu vends très bien la chose.
Vil tentateur ! :gener:


RE: [Ruby on Rails] Créer un espace d'administration - Sephi-Chan - 12-10-2009

Ruby on Rails a une communauté anglophone conséquente. C'est très facile de trouver de l'aide entre le salon IRC, Google et la documentation.

La documentation, d'ailleurs. Elle n'est finalement pas si mauvaise que ça (c'est juste que celle de PHP est encore mieux, mais le langage en a plus besoin tant il est bordélique), il faut juste en prendre un peu l'habitude et apprendre à utiliser des API et autres références. Bien sûr, on trouve quand même des ressources cool, comme http://guides.rubyonrails.org/.

J'étofferai la liste quand j'aurais le temps.

Sinon, si tu veux apprendre Ruby et Rails, je peux t'aider… Cf. [Bug Spirit] Recherche personne motivée qui souhaite apprendre Ruby on Rails. Smile


Sephi-Chan


RE: [Ruby on Rails] Créer un espace d'administration - Plume - 12-03-2010

Putain ! J'trouve pas comment on fait pour qu'il aille chercher les vues qui sont dans views/administration/categories/xxxx.html.erb plutôt que views/categories/xxxx.html.erb.

[Edition] Putain ! C'est bon ! Par contre, j'ai d'autres problèmes que j'comprends pas (encore..)