239 votes

Rails : Comment fonctionne le bloc respond_to ?

Je passe par le Démarrer avec Rails et je me suis embrouillé avec la section 6.7. Après avoir généré un échafaudage, je trouve le bloc auto-généré suivant dans mon contrôleur :

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
  end
end

J'aimerais comprendre comment le bloc respond_to fonctionne réellement. Quel type de variable est le format ? Les méthodes .html et .json sont-elles des méthodes de l'objet format ? Le site documentation pour

ActionController::MimeResponds::ClassMethods::respond_to

ne répond pas à la question.

1 votes

Ce serait bien si je pouvais faire un lien vers la documentation de ActionController::MimeResponds::ClassMethods::respond_to mais api.rubyonrails.org ne semble pas aimer les hyperliens directs...

1 votes

Respond_to prend la fin de l'appel (par exemple blah.html, blah.json, etc) et correspond à la vue spécifiée. D'autres réponses peuvent être XML, CSV et bien d'autres encore, en fonction de l'application.

5 votes

Comment cela "correspond à la vue spécifiée" ?

219voto

Parched Squid Points 3713

Je suis nouveau dans le monde de Ruby et je suis bloqué par ce même code. Les parties sur lesquelles j'étais bloqué étaient un peu plus fondamentales que certaines des réponses que j'ai trouvées ici. Cela peut aider ou non quelqu'un.

  • respond_to est une méthode de la superclasse ActionController .
  • il prend un bloc, qui est comme un délégué. Le bloc est de do jusqu'à end con |format| en tant qu'argument du bloc.
  • respond_to exécute votre bloc, en transmettant un répondeur dans le bloc format argument.

http://api.rubyonrails.org/v4.1/classes/ActionController/Responder.html

  • El Responder ne contient PAS de méthode pour .html o .json mais nous appelons ces méthodes de toute façon ! Cette partie m'a fait perdre la tête.
  • Ruby possède une fonctionnalité appelée method_missing . Si vous appelez une méthode qui n'existe pas (comme json o html ), Ruby appelle le method_missing à la place.

http://ruby-metaprogramming.rubylearning.com/html/ruby_metaprogramming_2.html

  • El Responder utilise sa classe method_missing comme une sorte d'enregistrement. Lorsque nous appelons 'json', nous lui demandons de répondre aux demandes avec l'extension .json en les sérialisant en json. Nous devons appeler html sans arguments pour lui demander de traiter les requêtes .html de la manière par défaut (en utilisant des conventions et des vues).

Il pourrait être écrit comme ceci (en utilisant un pseudo-code de type JS) :

// get an instance to a responder from the base class
var format = get_responder()

// register html to render in the default way
// (by way of the views and conventions)
format.register('html')

// register json as well. the argument to .json is the second
// argument to method_missing ('json' is the first), which contains
// optional ways to configure the response. In this case, serialize as json.
format.register('json', renderOptions)

Cette partie m'a beaucoup perturbé. Je la trouve toujours peu intuitive. Ruby semble utiliser cette technique assez souvent. La classe entière ( responder ) devient la mise en œuvre de la méthode. Afin d'exploiter method_missing nous avons besoin d'une instance de la classe, nous sommes donc obligés de passer une callback dans laquelle ils passent l'objet de type méthode. Pour quelqu'un qui a codé dans des langages de type C pendant une vingtaine d'années, c'est très rétrograde et peu intuitif pour moi. Non pas que ce soit mauvais ! Mais c'est quelque chose que beaucoup de personnes ayant ce genre de connaissances doivent comprendre, et je pense que c'est peut-être ce que le PO recherchait.

p.s. notez que dans le RdR 4.2 respond_to a été extrait dans intervenants gemme.

0 votes

Merci Craig, ce lien contient également une tonne d'informations utiles. method_missing en considérant que vous pouvez passer les arguments y un bloc !

4 votes

Meilleure réponse pour expliquer l'utilisation de method_missing() comme mécanisme d'enregistrement dans la classe Responder ! J'étais également très confus avec ce code.

1 votes

Les générateurs d'échafaudages Rails 6 semblent produire du code avec respond_to dans les contrôleurs, sans la gemme responders présente dans le Gemfile. Peut-être que la partie concernant respond_to qui est extrait dans la gemme du répondant, a été modifié ?

111voto

PhillipKregg Points 3702

Il s'agit d'un bloc de code Ruby qui tire parti d'une méthode d'aide de Rails. Si vous n'êtes pas encore familier avec les blocs, vous les verrez souvent en Ruby.

respond_to est une méthode d'aide Rails qui est attachée à la classe Controller (ou plutôt, à sa super classe). Elle fait référence à la réponse qui sera envoyée à la vue (qui sera envoyée au navigateur).

Le bloc dans votre exemple formate les données - en passant dans un paramètre "format" dans le bloc - à envoyer du contrôleur à la vue chaque fois qu'un navigateur fait une demande de données html ou json.

Si vous êtes sur votre machine locale et que vous avez configuré votre échafaudage de poste, vous pouvez vous rendre à l'adresse suivante http://localhost:3000/posts et vous verrez tous vos messages au format html. Mais, si vous tapez ceci : http://localhost:3000/posts.json vous verrez alors tous vos messages dans un objet json envoyé par le serveur.

C'est très pratique pour créer des applications lourdes en javascript qui ont besoin de passer du json dans les deux sens depuis le serveur. Si vous le souhaitez, vous pouvez facilement créer une api json sur votre back-end rails, et ne passer qu'une vue - comme la vue index de votre contrôleur Post. Vous pourriez alors utiliser une bibliothèque javascript comme Jquery o Backbone (ou les deux) pour manipuler les données et créer votre propre interface. On les appelle interfaces utilisateur asynchrones et ils deviennent vraiment populaires (Gmail en est un). Ils sont très rapides et offrent à l'utilisateur final une expérience plus proche de celle d'un ordinateur de bureau sur le web. Bien entendu, il ne s'agit là que d'un des avantages du formatage de vos données.

La façon Rails 3 d'écrire ceci serait la suivante :

    class PostsController < ApplicationController
      # GET /posts
      # GET /posts.xml

      respond_to :html, :xml, :json

      def index
        @posts = Post.all

        respond_with(@posts)
      end

#
# All your other REST methods
#

end

En mettant respond_to :html, :xml, :json en haut de la classe, vous pouvez déclarer tous les formats que vous voulez que votre contrôleur envoie à vos vues.

Ensuite, dans la méthode du contrôleur, tout ce que vous avez à faire est de répondre_avec(@quelque_objet_que_vous_avez)

Cela simplifie juste un peu plus votre code que ce que Rails génère automatiquement.

Si vous voulez en savoir plus sur les rouages de ce ...

D'après ce que j'ai compris, Rails procède à une introspection des objets afin de déterminer quel sera le format réel. La valeur de la variable 'format' est basée sur cette introspection. Rails peut faire beaucoup de choses avec un petit peu d'information. Vous seriez surpris de voir jusqu'où peut aller un simple @post ou :post.

Par exemple, si j'ai un fichier partiel _user.html.erb qui ressemble à ceci :

_user.html.erb

<li>    
    <%= link_to user.name, user %>
</li>

Ensuite, ce seul élément dans ma vue d'index indiquerait à Rails qu'il doit trouver le partiel "users" et itérer à travers tous les objets "users" :

index.html.erb

 <ul class="users">
   <%= render @users %>     
 </ul>

indiquerait à Rails qu'il doit trouver la partie "user" et itérer à travers tous les objets "users" :

Vous trouverez peut-être cet article de blog utile : http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

Vous pouvez également consulter la source : https://github.com/rails/rails

1 votes

Bon conseil sur la méthode rails3. J'essaie toujours de comprendre le bloc respond_to, et ce que l'argument |format| du bloc reçoit.

4 votes

Bonne réponse, mais elle ne dit rien de spécifique sur la variable de format qui est passée dans le bloc. Dans l'exemple donné, il y a format.html et format.json. Est-ce que ces deux variables sont transmises à respond_to et c'est ensuite respond_to qui décide de leur utilisation ?

0 votes

Quand était respond_to y respond_with introduit ? J'utilise rails 2.3.5 et je reçois NoMethodError (undefined method respond_to)

10voto

Nobita Points 9046

D'après ce que je sais, respond_to est une méthode attachée à l'ActionController, donc vous pouvez l'utiliser dans chaque contrôleur, car tous héritent de l'ActionController. Voici la méthode respond_to de Rails :

def respond_to(&block)
  responder = Responder.new(self)
  block.call(responder)
  responder.respond
end

Vous lui passez un bloc comme je le montre ici :

respond_to <<**BEGINNING OF THE BLOCK**>> do |format|
  format.html
  format.xml  { render :xml => @whatever }
end <<**END OF THE BLOCK**>>

El |format| est l'argument que le bloc attend, donc dans la méthode respond_to nous pouvons l'utiliser. Comment ?

Si vous remarquez que nous passons le bloc avec un préfixe & dans la méthode respond_to, et nous faisons cela pour traiter ce bloc comme un Proc. Puisque l'argument a les ".xml", ".html", nous pouvons les utiliser comme des méthodes à appeler.

Ce que nous faisons essentiellement dans la classe respond_to, c'est appeler les méthodes ".html, .xml, .json" à une instance de la classe Responder.

1 votes

La source de respond_to dans la documentation de l'API est différente de celle que vous avez incluse, et m'a induit en erreur. Votre extrait me fait comprendre plus clairement que l'argument du bloc de format est transmis à un objet Responder. La documentation du Responder semble répondre à la question, je la lis maintenant.

7voto

rnicholson Points 2110

J'aimerais comprendre comment le bloc respond_to fonctionne réellement. Quel type de variable type de variable est le format ? Les méthodes .html et .json sont-elles des méthodes de l'objet format sont-elles des méthodes de l'objet format ?

Afin de comprendre ce que format est, vous pourriez d'abord regarder la source pour respond_to mais vous découvrirez rapidement que ce que vous devez vraiment regarder est le code pour récupération_réponse_des_mimes .

D'ici, vous verrez que le bloc qui a été transmis à respond_to (dans votre code), est en fait appelé et passé avec une instance de Collecteur (qui, dans le bloc, est référencé comme format ). Collector génère essentiellement des méthodes (je crois au démarrage de Rails) en fonction de ce que types de mime Les rails sont connus.

Donc, oui, le .html y .json sont des méthodes définies (au moment de l'exécution) sur le collecteur (alias format ).

3voto

Catharz Points 678

La méta-programmation derrière l'enregistrement des répondeurs (voir la réponse de Parched Squid) permet également de faire des choses astucieuses comme celle-ci :

def index
  @posts = Post.all

  respond_to do |format|
    format.html  # index.html.erb
    format.json  { render :json => @posts }
    format.csv   { render :csv => @posts }
    format.js
  end
end

La ligne csv fera en sorte que to_csv soit appelé sur chaque message lorsque vous visitez /posts.csv. Cela permet d'exporter facilement des données au format CSV (ou tout autre format) à partir de votre site rails.

La ligne js fera en sorte qu'un fichier javascript /posts.js (ou /posts.js.coffee) soit rendu/exécuté. J'ai trouvé que c'était un moyen léger de créer un site compatible Ajax utilisant des pop-ups jQuery UI.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X