Los rieles responden_con: ¿cómo funciona?

128

He estado leyendo aquí y allá acerca de cuán genial es el respond_withmétodo en Rails 3. Pero ni siquiera puedo encontrar una referencia en las API de Rails o buscando en la fuente. ¿Alguien puede explicarme cómo funciona (qué opciones puede usar, etc.) o señalarme el lugar donde está implementado para que pueda leer el código por mi cuenta?

jaydel
fuente

Respuestas:

128

Actualización para Rails 4.2+

#respond_withy ::respond_to( método de clase nb ) ya no son parte de Rails . Fueron migrados a la gema de respondedores de terceros a partir de Rails 4.2 ( notas de lanzamiento / commit con fecha de agosto de 2014). Si bien los respondedores no están incluidos en Rails de manera predeterminada, es una dependencia de Devise y, por lo tanto, está disponible en muchas aplicaciones de Rails.

El #respond_to método de instancia, sin embargo, sigue siendo parte de Rails (5.2rc1 a partir de este escrito).

La documentación oficial de la API de Rails ActionController::MimeRespondsexplica cómo #respond_tofunciona. La documentación original de Rails Guides comenta #respond_withy ::respond_toaún se puede encontrar en el código fuente de la gema del respondedor .


Respuesta original

El código para los respondedores se basa en una clase y un módulo. MimeResponds que se incluye en ActionController :: Base , la clase de la que ApplicationControllerhereda. Luego está ActionController :: Responder que proporciona el comportamiento predeterminado cuando se utiliza respond_con.


Por defecto, el único comportamiento que proporciona rails en la respuesta es un intento implícito de representar una plantilla con un nombre que coincida con la acción. Cualquier cosa más allá de eso requiere más instrucciones dentro de la acción, o una respuesta personalizada para llamar con un bloque para manejar respuestas de formato múltiple.

Como la mayoría de los controladores usan un patrón de personalización bastante común, los respondedores proporcionan un nivel adicional de abstracción al introducir un comportamiento más predeterminado. Lea las acciones que llaman a to_xml / to_json para formatos específicos, y las acciones de mutadores que proporcionan lo mismo, así como redireccionamientos para acciones exitosas de mutadores.


Hay algunas oportunidades para personalizar cómo se comportan los respondedores, desde ajustes sutiles hasta anular o extender completamente el comportamiento.

Nivel de clase: respond_to

Aquí especifica los formatos que debe manejar el Respondedor. Los formatos se pueden personalizar a qué acciones se aplicarán. Cada formato se puede especificar con llamadas separadas, lo que permite la personalización completa de las acciones para cada formato.

# Responds to html and json on all actions
respond_to :html, :json

# Responds to html and json on index and show actions only.
respond_to :html, :json, :only => [:index,:show]

# Responds to html for everything except show, and json only for index, create and update
respond_to :html, :except => [:show]
respond_to :json, :only => [:index, :create, :update]

Nivel de clase: responder

Este es un atributo de clase que contiene el respondedor. Esto puede ser cualquier cosa que responda a una llamada, lo que significa que puede usar un proc / lambda o una clase que responda a una llamada. Otra alternativa es mezclar uno o módulos con el respondedor existente para sobrecargar los métodos existentes, aumentando el comportamiento predeterminado.

class SomeController < ApplicationController
  respond_to :json

  self.responder = proc do |controller, resources, options|
    resource = resources.last
    request = controller.request
    if request.get?
      controller.render json: resource
    elsif request.post? or request.put?
      if resource.errors.any?
        render json: {:status => 'failed', :errors => resource.errors}
      else
        render json: {:status => 'created', :object => resource}
      end
    end
  end
end

Si bien puede haber algunos casos de uso de borde interesantes, es más probable que extender o mezclar módulos en el respondedor predeterminado sean patrones más comunes. En cualquier caso, las opciones que son relevantes son los recursos y las opciones, ya que se transfieren desde from respond_with.

Nivel de instancia: respond_with

Las opciones aquí son las que se pasarían a renderizar o redirigir en su controlador, pero solo se incluyen para escenarios de éxito. Para las acciones GET, estas serían las llamadas de renderizado, para otras acciones, estas serían las opciones de redireccionamiento. Probablemente la más útil de estas es la :locationopción, que se puede usar para anular esa ruta de redireccionamiento en caso de que los argumentos para responder con no sean suficientes para construir la URL correcta.

# These two are essentially equal
respond_with(:admin, @user, @post)
respond_with(@post, :location => admin_user_post(@user, @post)

# Respond with a 201 instead of a 200 HTTP status code, and also
# redirect to the collection path instead of the resource path
respond_with(@post, :status => :created, :location => posts_path)

# Note that if you want to pass a URL with a query string
# then the location option would be needed.
# /users?scope=active
respond_with(@user, :location => users_path(:scope => 'active'))

Como alternativa, la gema del respondedor no solo proporciona algunos módulos para anular algunos de los comportamientos predeterminados. Anula el respondedor predeterminado con una clase anónima que amplía el respondedor predeterminado y proporciona un método de nivel de clase para mezclar módulos personalizados a esta clase. El más útil aquí es el respondedor flash, que proporciona un conjunto predeterminado de flashes, delegando la personalización al sistema I18n, config/locales/en.ymlde manera predeterminada.

Algunos ejemplos de respondedores personalizados que he usado en proyectos anteriores incluyen un respondedor que decoraba automáticamente mis recursos y proporcionaba un conjunto predeterminado de títulos de página con una interfaz para personalizar o anular fácilmente el título de la página.

Racimo
fuente
1
Creo que significa (en el cuerpo de la clase) self.responder =como se acaba responder =asignará a un local de
horseyguy
¡Gracias! ¡La existencia de la locationopción era la información que necesitaba!
JellicleCat
1
¿Esa explicación sigue siendo relevante para Rails 4/5? Escuché que respond_withsería obsoleto, pero no logro averiguar por qué.
Arnlen
1
@Arnlen, respond_with se extrajo como una gema separada ' respondedores '
Nick Roz
Tenga en cuenta que para config/locales/en.ymlque funcionen los flashes , necesita responders :flashen la parte superior de su controlador.
bjnord