Dans notre série d’articles sur les bases de Ruby on Rails, explorons aujourd’hui la magie de respond_to.
Le mécanisme respond_to
est présent depuis les toutes premières versions de Ruby on Rails.
Il permet depuis un contrôleur d’offrir des réponses différentes selon le format demandé.
Par exemple si je demande l’affichage de mes utilisateurs en JSON, XML ou HTML, le format de rendu sera différent.
C’est particulièrement pratique si votre application web possède un front (visible en HTML) mais qu’elle agit également comme une API, par exemple au format JSON pour interagir avec une application mobile.
Prenons un contrôleur tout ce qu’il y a de plus basique:
class ProductsController < ApplicationController
def index
@products = Product.all
end
end
Ruby on Rails utilise 2 moyens pour déterminer le format demandé.
Le premier est prioritaire sur le second, vérifions avec curl
:
curl -i -H "Accept: application/json" http://localhost:8000/products.xml
Voici la partie du résultat qui nous intéresse:
Missing template products/index, application/index with {:locale=>[:en], :formats=>[:xml], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}. Searched in: * "/Users/fuse/tmp/respond/app/views"
On voit bien que le format recherché est XML. Ce format n’existe d’ailleurs pas de notre côté.
À noter que le contrôleur n’a pas besoin de respond_to
explicite quand la vue est présente,
quelque soit le format.
Si nous créons une fichier views/products/index.html.erb
, ou views/products/index.xml
…
le contrôleur rendra automatiquement la vue correspondante au format, autrement nous
aurons un Template is missing
.
Toutefois dès lors que nous définissons un bloc respond_to
, nous devons définir
tous les formats acceptés, le mapping ne se fait plus automatiquement avec les vues.
Vous aurez remarqué que Rails «connaît» un certain nombre de formats.
Ces formats représentent le content-type du fichier, autrement appelé type MIME.
Vous pouvez les lister avec Mime::EXTENSION_LOOKUP
.
Dans Rails, chaque type est en fait un sous module de MIME. Exemple:
Mime::CSV
=> #<Mime::Type:0x007f8954b5e3b8 @synonyms=[], @symbol=:csv, @string="text/csv">
Si dans une action de votre contrôleur vous n’avez pas de respond_to
et que vous demandez par exemple products.foo
,
c’est le format HTML qui sera utilisé, et ce même si vos entêtes demandent un format qui existe.
C’est tout à fait normal car les entêtes envoyés par le navigateur peuvent contenir à peu près n’importe quoi.
curl -i -H "Accept: application/xml" http://localhost:8000/products.foo
renverra donc la liste des produits en HTML, même si le fichier index.xml est présent.
Définir votre propre format est trivial, un initializer est prévu pour cela,
config/initializers/mime_types.rb
.
Mime::Type.register "application/vnd.ms-excel", :xls
À partir de là vous pourrez gérer votre format Excel dans votre bloc respond_to
.
Si vous avez besoin de manipuler le format, celui ci se trouve directement
dans la requête (request.format
).
Exemple:
respond_to do |format|
format.any(:xml, :foo) { render xml: @products }
format.xls {
# Charge à notre code d'implémenter le to_xls
render xls: @products.to_xls
}
end
Pour simplifier un peu plus Ruby on Rails a introduit le mécanisme
respond_with
.
Il s’agit de définir au niveau contrôleur les formats auxquels on répond, puis de répondre avec un objet.
class ProductsController < ApplicationController
respond_to :json, :xml
def index
@products = Product.all
respond_with @products
end
end
Par défaut Rails utilise le builder intégré, c’est à dire
que dans le cas de XML il fera un rendu de @products.to_xml
,
mais il parfaitement possible de définir sa propre vue.
À noter que les formats qui ne sont pas explicitement spécifiés
ne sont pas accessibles. Ici l’URL /products
n’affichera pas la version HTML.
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.