ruby-on-rails - tutorial - ruby on rails windows




Rails: Comment fonctionne le bloc respond_to? (6)

Je parcours le guide Getting Started with Rails et je suis confus 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

Je voudrais comprendre comment le bloc respond_to fonctionne réellement. Quel type de variable est le format? Les méthodes .html et .json de l'objet format? La documentation pour ActionController::MimeResponds::ClassMethods::respond_to ne répond pas à la question.


Je voudrais comprendre comment le bloc respond_to fonctionne réellement. Quel type de variable est le format? Les méthodes .html et .json de l'objet format?

Afin de comprendre quel format est, vous pouvez d'abord regarder la source de respond_to , mais rapidement, vous trouverez que ce que vous devez vraiment regarder est le code pour retrieve_response_from_mimes .

De là, vous verrez que le bloc qui a été passé à respond_to (dans votre code), est en fait appelé et passé avec une instance de Collector (qui dans le bloc est référencée comme format ). Collector génère essentiellement des méthodes (je crois au démarrage de Rails) basées sur ce que les types de mime rails connaissent.

Donc, oui, le .html et .json sont des méthodes définies (à l'exécution) sur la classe Collector (aka format ).


Quel type de variable est le format?

A partir d'un POV java, le format est une implémentation d'une interface anonyme. Cette interface a une méthode nommée pour chaque type mime. Lorsque vous invoquez l'une de ces méthodes (en lui passant un bloc), si les rails estiment que l'utilisateur veut ce type de contenu, il appelle votre bloc.

La torsion, bien sûr, est que cet objet colle anonyme n'implémente pas réellement une interface - il attrape dynamiquement les appels de méthode et fonctionne si c'est le nom d'un type MIME dont il a connaissance.

Personnellement, je pense que ça a l'air bizarre: le bloc que vous passez est exécuté . Il serait plus logique pour moi de passer un hachage d'étiquettes et de blocs de format. Mais - c'est comme ça que ça se passe dans RoR, semble-t-il.


C'est un bloc de code Ruby qui tire parti d'une méthode d'assistance Rails. Si vous n'êtes pas encore familier avec les blocs, vous les verrez beaucoup dans Ruby.

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

Le bloc dans votre exemple est le formatage des 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 pour les données html ou json.

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

C'est très pratique pour faire des applications lourdes javascript qui ont besoin de transmettre json aller et retour du serveur. Si vous le vouliez, vous pourriez facilement créer un json api sur le backend de votre rail, et ne passer qu'une vue - comme l'index de votre contrôleur Post. Ensuite, vous pouvez utiliser une bibliothèque javascript comme Jquery ou Backbone (ou les deux) pour manipuler les données et créer votre propre interface. Ceux-ci sont appelés interfaces asynchrones et ils deviennent vraiment populaires (Gmail en est un). Ils sont très rapides et offrent à l'utilisateur final une expérience de type bureau sur le Web. Bien sûr, ceci n'est qu'un avantage du formatage de vos données.

The Rails 3 façon 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 respond_with (@whatever_object_you_have)

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

Si vous voulez savoir sur le fonctionnement interne de cette ...

D'après ce que je comprends, Rails introspecte les objets pour déterminer quel sera le format réel. La valeur des variables 'format' est basée sur cette introspection. Rails peut faire beaucoup avec un peu d'info. Vous seriez surpris de voir jusqu'où ira un simple @post ou post.

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

_user.html.erb

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

Ensuite, cela seul dans mon index permettrait à Rails de savoir qu'il devait trouver les 'utilisateurs' partiels et parcourir tous les objets 'utilisateurs':

index.html.erb

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

laisserait savoir à Rails qu'il devait trouver l''utilisateur' partiel et parcourir tous les objets 'utilisateurs':

Vous pouvez trouver ce 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 parcourir la source: https://github.com/rails/rails


C'est un peu démodé, par Ryan Bigg qui fait un excellent travail en expliquant ceci ici:

http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/

En fait, ce pourrait être un peu plus de détails que ce que vous cherchiez. En fin de compte, il se passe beaucoup de choses dans les coulisses, y compris un besoin de comprendre comment les types MIME sont chargés.


Il y a une chose de plus que vous devriez savoir - MIME.

Si vous devez utiliser un type MIME et qu'il n'est pas supporté par défaut, vous pouvez enregistrer vos propres gestionnaires dans config / initializers / mime_types.rb:

Mime::Type.register "text/markdown", :markdown


Je suis nouveau à Ruby et suis resté coincé à ce même code. Les parties sur lesquelles j'ai été accroché étaient un peu plus fondamentales que certaines des réponses que j'ai trouvées ici. Cela peut ou peut ne pas aider quelqu'un.

  • respond_to est une méthode sur la superclasse ActionController .
  • il faut un bloc, ce qui est comme un délégué. Le bloc est de do jusqu'à la end , avec |format| comme un argument pour le bloc.
  • respond_to exécute votre bloc, en passant un Responder dans l'argument de format .

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

  • Le Responder ne contient PAS de méthode pour .html ou .json , mais nous appelons ces méthodes quand même! Cette partie m'a lancé pour une boucle.
  • Ruby a une fonction appelée method_missing . Si vous appelez une méthode qui n'existe pas (comme json ou html ), Ruby appelle la méthode method_missing place.

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

  • La classe Responder utilise son method_missing comme une sorte d'enregistrement. Quand nous appelons 'json', nous lui disons de répondre aux requêtes avec l'extension .json en sérialisant à json. Nous devons appeler html sans argument pour lui dire 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 a confondu le diable hors de moi. Je trouve toujours ça non intuitif. Ruby semble utiliser cette technique un peu. La classe entière ( responder ) devient l'implémentation de la méthode. Afin de tirer parti de method_missing , nous avons besoin d'une instance de la classe, nous sommes donc obligés de passer un callback dans lequel ils passent l'objet de type méthode. Pour quelqu'un qui a codé dans des langages C-like depuis 20 ans, c'est très rétrograde et non intuitif pour moi. Pas que ce soit mauvais! Mais c'est quelque chose que beaucoup de personnes ayant ce type d'expérience ont besoin de comprendre, et je pense que c'est peut-être ce que le PO voulait dire.

ps note que dans RoR 4.2 respond_to été extrait dans les responders gem.







ruby-on-rails