Rieles: ¿Cómo funciona el bloque responder_?

Estoy repasando la guía Getting Started with Rails y me confundí con la sección 6.7. Después de generar un andamio, encuentro el siguiente bloque autogenerado en mi controlador:

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

Me gustaría entender cómo funciona el bloque responder_ a realmente funciona. ¿Qué tipo de variable es formato? ¿Están los métodos .html y .json del objeto de formato? La documentación de ActionController::MimeResponds::ClassMethods::respond_to responder_ no responde la pregunta.

Soy nuevo en Ruby y me quedé atrapado en este mismo código. Las partes que obtuve me parecieron un poco más fundamentales que algunas de las respuestas que encontré aquí. Esto puede o no ayudar a alguien.

  • respond_to es un método en la superclase ActionController .
  • toma un bloque, que es como un delegado. El bloque es de do hasta end , con |format| como un argumento para el bloque.
  • responder_a ejecuta su locking, pasando un Respondedor al argumento de format .

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

  • El Responder NO contiene un método para .html o .json , ¡pero llamamos a estos métodos de todos modos! Esta parte me lanzó a un bucle.
  • Ruby tiene una característica llamada method_missing . Si llama a un método que no existe (como json o html ), Ruby llama al método method_missing lugar.

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

  • La clase Responder usa su method_missing como un tipo de registro. Cuando llamamos a ‘json’, le estamos diciendo que responda a solicitudes con la extensión .json serializando en json. Necesitamos llamar a html sin argumentos para decirle que maneje las solicitudes .html de la manera predeterminada (usando convenciones y vistas).

Podría escribirse así (utilizando pseudocódigo similar a 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) 

Esta parte me confundió. Todavía lo encuentro poco intuitivo. Ruby parece usar esta técnica bastante. Toda la clase ( responder ) se convierte en la implementación del método. Para aprovechar method_missing , necesitamos una instancia de la clase, por lo que estamos obligados a pasar una callback en la que pasan el objeto similar al método. Para alguien que ha codificado en C-como los idiomas durante 20 años, esto es muy atrasado y poco intuitivo para mí. ¡No es malo! Pero es algo que mucha gente con ese tipo de trasfondo necesita para entenderse, y creo que podría ser lo que buscaba el OP.

Observe que en RoR 4.2 se extrajo respond_to en la gem del respondedor .

Este es un bloque de código de Ruby que aprovecha el método de ayuda de Rails. Si aún no estás familiarizado con los bloques, los verás mucho en Ruby.

respond_to es un método de ayuda de Rails que está conectado a la clase Controller (o más bien, su superclase). Hace referencia a la respuesta que se enviará a la Vista (que va al navegador).

El bloque en su ejemplo está formateando datos – pasando un parámetro de ‘formato’ en el bloque – para ser enviados desde el controlador a la vista cada vez que un navegador realiza una solicitud de datos html o json.

Si está en su máquina local y tiene configurada su estructura de andamio Post, puede ir a http://localhost:3000/posts y verá todas sus publicaciones en formato html. Pero, si escribe esto: http://localhost:3000/posts.json , verá todas sus publicaciones en un objeto json enviado desde el servidor.

Esto es muy útil para hacer javascript aplicaciones pesadas que necesitan pasar json hacia adelante y hacia atrás desde el servidor. Si lo desea, puede crear fácilmente una api json en el back-end de sus raíles, y solo pasar una vista, como la vista de índice de su controlador Post. Luego, podría usar una biblioteca de JavaScript como Jquery o Backbone (o ambas) para manipular datos y crear su propia interfaz. Estos se denominan UI asincrónicas y se están volviendo muy populares (Gmail es uno). Son muy rápidos y brindan al usuario final una experiencia más similar a la de un escritorio en la web. Por supuesto, esto es solo una ventaja de formatear sus datos.

La manera en que Rails 3 escribe esto sería esta:

  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 

Al poner respond_to :html, :xml, :json en la parte superior de la clase, puede declarar todos los formatos que desea que su controlador envíe a sus vistas.

Luego, en el método del controlador, todo lo que tienes que hacer es responder_con (@whatever_object_you_have)

Simplemente simplifica tu código un poco más de lo que Rails autogenera.

Si quieres saber sobre el funcionamiento interno de esto ...

Por lo que entiendo, Rails introspecta los objetos para determinar cuál va a ser el formato real. El valor de las variables de "formato" se basa en esta introspección. Rails puede hacer mucho con un poco de información. Te sorprendería lo lejos que irá un simple @post o: post.

Por ejemplo, si tuviera un archivo parcial _user.html.erb que se veía así:

_user.html.erb

 
  • < %= link_to user.name, user %>
  • Entonces, esto solo en mi vista de índice le haría saber a Rails que necesitaba encontrar los 'usuarios' parciales e iterar a través de todos los objetos de 'los usuarios':

    index.html.erb

      
      < %= render @users %>

    le haría saber a Rails que necesitaba encontrar el 'usuario' parcial e iterar a través de todos los objetos de 'los usuarios':

    Puede encontrar esta publicación de blog útil: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

    También puede leer detenidamente la fuente: https://github.com/rails/rails

    Por lo que sé, responder_a es un método adjunto al ActionController, por lo que puede usarlo en todos los controladores, ya que todos heredan del ActionController. Aquí está el método Rails respond_to:

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

    Lo está pasando un bloque , como muestro aquí:

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

    El | formato | parte es el argumento que el bloque está esperando, por lo que dentro del método responder_ podemos usar eso. ¿Cómo?

    Bueno, si nota que pasamos el bloque con un prefijo y en el método responder_, y lo hacemos para tratar ese bloque como un Proc. Como el argumento tiene el “.xml”, “.html”, podemos usarlo como métodos para llamar.

    Lo que básicamente hacemos en la clase respond_to es llamar a los métodos “.html, .xml, .json” a una instancia de una clase Responder.

    Me gustaría entender cómo funciona realmente el bloque responder_a. ¿Qué tipo de variable es formato? ¿Están los métodos .html y .json del objeto de formato?

    Para comprender qué format es, primero puede ver la fuente de respond_to , pero rápidamente encontrará que lo que realmente necesita ver es el código para retrieve_response_from_mimes .

    Desde aquí, verá que el bloque que se pasó a respond_to (en su código), en realidad se llama y pasa con una instancia de Colector (que dentro del bloque se denomina format ). Collector básicamente genera métodos (creo en el inicio de Rails) en función de los tipos de mime que conoce los Rails.

    Entonces, sí, los .html y .json son métodos definidos (en tiempo de ejecución) en la clase Collector ( format aka).

    La meta-progtwigción detrás del registro de respondedores (ver la respuesta de Squid Parked) también le permite hacer cosas ingeniosas como esta:

     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 línea csv hará que se llame a_csv en cada publicación cuando visite /posts.csv. Esto hace que sea fácil exportar datos como CSV (o cualquier otro formato) desde su sitio de Rails.

    La línea js provocará que se renderice / ejecute un archivo javascript /posts.js (o /posts.js.coffee). He descubierto que es una forma ligera de crear un sitio habilitado para Ajax utilizando ventanas emergentes de jQuery UI.

    ¿Qué tipo de variable es formato?

    Desde un POV java, el formato es una implementación de una interfaz anónima. Esta interfaz tiene un método nombrado para cada tipo de mimo. Cuando invocas uno de esos métodos (pasándole un bloque), entonces si los Rails sienten que el usuario quiere ese tipo de contenido, invocará tu locking.

    El giro, por supuesto, es que este objeto de pegamento anónimo no implementa realmente una interfaz: capta las llamadas al método de forma dinámica y funciona si es el nombre de un tipo de mimo que conoce.

    Personalmente, creo que se ve raro: el bloque que pasas se ejecuta . Tendría más sentido para mí pasar un hash de tags y bloques de formato. Pero, así es como se hace en RoR, parece.

    Hay una cosa más que debes tener en cuenta: MIME.

    Si necesita utilizar un tipo MIME y no es compatible por defecto, puede registrar sus propios manejadores en config / initializers / mime_types.rb:

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

    Esto es un poco anticuado, por Ryan Bigg hace un gran trabajo al explicar esto aquí:

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

    De hecho, podría ser un poco más detallado de lo que estabas buscando. Resulta que hay muchas cosas detrás de escena, incluida la necesidad de comprender cómo se cargan los tipos MIME.

    “Formato” es su tipo de respuesta. Podría ser json o html, por ejemplo. Es el formato de la salida que recibirá su visitante.