Boire ou coder ... Pourquoi choisir?
Publié le 16 mars 2010 23:00

La puissance de l'intégration de rack dans rails 3

Cet article est fortement inspiré (mais n'est pas une traduction) de Rails and Merb Merge: Rack

Rack est une interface entre votre serveur web et votre application basé sur le standard CGI mais sans ses caractéristiques globales (variables d'environnement et sortie standard).

Dans Rails 2.3

Depuis Rails 2.3, toute application développée autour du framework tourne avec Rack. L'implémentation de rack est la suivante :

  • ActionController::Dispatcher.new est l'application rack de base
  • Le parseur de paramètres (ActionController::ParamsParser)est implémenté en tant que middleware
  • Le routeur est une application rack qui dispatche vers les contrôleurs
  • Chaque contrôleur est une application rack

cela a donc permis d'implémenter la notion de metal, des applications rack tournant autour de Ruby.

Vous pouvez trouver un exemple de metal dans mon article interdire l'accès aux crawlers dans l'environnement de développement.

Cependant les metal n'existent plus dans rails 3. Vous allez comprendre pourquoi dans cet article.

Mais ne nous attardons pas sur les choses qui sont vouées à disparaitre et passons plutôt directement à ce qui est intéressant : les nouveautés apportées par l'implémentation de Rack dans Rails 3.

Dans Rails 3

Vous l'avez déjà vu, Rails 3 implémente le concept d'application. Chaque application est un objet contenant un routeur et des paramètres et configuration ... Mais avant tout une application Rack !

Par conséquent les 10 lignes de code suivantes sont une application Rails 3 qui fonctionne. Dans un fichier nommé config.ru, placez :

require "action_controller/railtie"
 
class FooController < ActionController::Base
  def bar
    self.response_body = "Hello World !"
  end
end
 
class MyApp < Rails::Application
   config.session_store :disabled
 
   routes.draw do
     root :to => "foo#bar"
  end
end
 
run MyApp

Lancez l'application : rackup -p 4000. Rendez-vous sur localhost:4000 et vous verrez un bel "Hello World". Vos applications les plus simples n'ont plus rien à envier aux applications Sinatra.

Nous avons vu plus haut que Rails 2.3 commençait déjà à être conçu autour de middlewares rack. Dans cette nouvelle branche, cette intégration est encore plus flagrante. En effet Rails 3 inclue les fonctionnalités suivantes chacune dans un middleware différent :

  • Un middleware exécutant les preparation callbacks
  • Un middleware pour lire et écrire les cookies
  • Un middleware qui nettoie les flash déjà affichés
  • Un middleware qui gère les requêtes HEAD
  • Un middleware vérifiant les IP spoofing
  • Un middleware servant à rendre les fichiers statiques
  • Un middleware de gestion des exceptions de bas niveau
  • Un middleware pour les divers stockages en session
  • Un middleware pour synchroniser les requêtes non thread-safe Dépends de Rack, pas de rails
  • Un middleware pour mesurer le temps d'exécution d'une requête Dépends de Rack, pas de rails
  • Un middleware permettant d'implémenter la sémantique de Send-file dans les divers serveurs Dépends de Rack, pas de rails
  • Un middleware permettant de détecter les requêtes PUT et DELETE transmises en POST Dépends de Rack, pas de rails

Bien évidemment vous pouvez dans votre application ajouter, réordonner ou supprimer des middlewares.

Le routeur

Le routeur de Rails 3 a également été réécrit afin d'être mieux implémenté dans Rack. C'est Rack::Mount. Celui-ci reconnait des URL et les dispatche vers n'importe quelle application, même si elles ne sont pas rails. Il est ainsi tout à fait possible de faire la chose suivante

Rails.application.routes.draw do
  match "/blog" => BlogApplication
end

Vous pouvez également mettre un symbole et donc avoir match :blog => BlogApplication

Vous n'avez plus qu'à écrire votre application de blog et elle sera intégrable dans votre application principale sous l'url /blog. Vous pouvez ainsi beaucoup plus aisément diviser votre application en de multiples modules, rendant chaque brique plus légère et donc plus aisée à développer.

Actions

Comme dit plus haut, chaque contrôleur est lui même une application Rack. Cela va même plus loin que cela puisque chaque action est en elle même une application rack ! Que vous pouvez exécuter indépendamment de l'application rails en elle même.

Cela se fait grâce à

MyController.action :index

Supposons par exemple un contrôleur Posts et une action show que vous souhaitez exécuter. Le fichier config.ru suivant sera exécuté sans problème avec rack.

class PostsController < ActionController::Base
  append_view_path "/path/to/views"
 
  def show
    render
  end
end
 
run ArticlesController.action(:show)

N'oubliez pas, bien évidemment, de remplacer "/path/to/views" par le réel chemin vers vos vues

Votre rendu et tous vos callbacks seront bien évidemment exécutés. En fait, en interne, c'est grosso modo ce que rails lui même fait.

Dans les tests

L'utilité de ceci est une plus grande facilité d'exécution des tests. Dans rails 2.3, si votre application dépends beaucoup de middlewares, ceux-ci seront assez difficile à tester dans vos tests fonctionnels car ils ne seront pas exécutés. C'est notamment le cas si vous utilisez devise. La solution trouvée est de mocker les fonctions implémentées par le middleware.

Avec Rack::Test, vous pouvez fortement simplifier cela. Reprenons notre méthode show précédente et testons la.

Tout d'abord en instanciant l'application en elle même.

class TestApplication < Test::Unit::TestCase
  include Rack::Test::Methods
 
  def app
    MyApplication
  end
 
  def test_get
    get "/posts/1"
    assert_equal "Hello world !", last_response.body
  end
end

Et puis comme on peut ne faire que un appel à l'action, on se prive pas

class TestPosts < Test::Unit::TestCase
  include Rack::Test::Methods
 
  def app
    PostsController.action(:show)
  end
 
  def test_get
    get "/posts/1"
    assert_equal "Hello world !", last_response.body
  end
end

Ici, nous sommes dans un article présentant des fonctionnalités. C'est donc un cas d'école. Avant de vous amuser à appeler directement une action dans vos tests, demandez vous si c'est vraiment DRY.

In fine

Si Rails 2.3 a commencé l'implémentation de Rack, Rails 3 plonge à plein nez dedans, s'intégrant pleinement avec l'application. Cela permet de rendre votre application beaucoup plus modulaire et puissante.

Nous avons vu ici une partie des nouvelles fonctionnalités du routeur. Mais ce n'est pas tout à ce niveau ! Attendez vous à d'autres :)

Commentaires

Postez un commentaire

Markdown activé