Rails respond_with: como funciona?

128

Eu tenho lido aqui e ali sobre o quão legal é o respond_withmétodo no Rails 3. Mas não consigo nem encontrar uma referência a ele nas APIs do Rails ou pesquisando na fonte. Alguém pode me explicar como funciona (que opções você pode usar, etc.) ou me indicar o local em que ele realmente foi implementado para que eu possa ler o código sozinho?

jaydel
fonte

Respostas:

128

Atualização para o Rails 4.2 ou superior

#respond_withe ::respond_to( método da classe nb ) não fazem mais parte do Rails . Eles foram migrados para a jóia de respondedores de terceiros a partir do Rails 4.2 ( notas de versão / confirmação de agosto de 2014). Embora o responders não esteja incluído no Rails por padrão, ele é uma dependência do Devise e, portanto, está disponível em muitos aplicativos do Rails.

O #respond_to método da instância, no entanto, ainda faz parte do Rails (5.2rc1 até o momento da redação).

A documentação oficial da API do Rails ActionController::MimeRespondsexplica como #respond_tofunciona. Os comentários originais da documentação dos Guias do Rails #respond_withe ::respond_toainda podem ser encontrados no código-fonte da gema dos respondedores .


Resposta original

O código para os respondentes é baseado em uma classe e um módulo. MimeResponds, que está incluído no ActionController :: Base , a classe da qual você ApplicationControllerherda. Depois, há o ActionController :: Responder, que fornece o comportamento padrão ao usar o respond_with.


Por padrão, o único comportamento que os trilhos fornecem na resposta é uma tentativa implícita de renderizar um modelo com um nome correspondente à ação. Qualquer coisa além disso requer mais instruções dentro da ação ou uma resposta personalizada para chamar com um bloco para lidar com várias respostas de formato.

Como a maioria dos controladores usa um padrão bastante comum de personalização, os respondedores fornecem um nível extra de abstração ao introduzir um comportamento mais padrão. Leia as ações que chamam to_xml / to_json para obter formatos específicos e as ações do mutador, fornecendo o mesmo e redirecionando para ações bem-sucedidas do mutador.


Existem algumas oportunidades para personalizar como os respondentes se comportam, de ajustes sutis a substituir ou estender completamente o comportamento.

Classe: respond_to

Aqui você especifica os formatos que o Respondente deve manipular. Os formatos podem ser personalizados para quais ações eles serão aplicados. Cada formato pode ser especificado com chamadas separadas, permitindo a personalização completa das ações 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]

Classe: responder

Este é um atributo de classe que mantém o respondedor. Isso pode ser qualquer coisa que responda à chamada, o que significa que você pode usar um proc / lambda ou uma classe que responde à chamada. Outra alternativa é misturar um ou módulos ao atendedor existente para sobrecarregar os métodos existentes, aumentando o comportamento padrão.

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

Embora possa haver alguns casos de uso de borda interessantes, é mais provável que estender ou misturar módulos no respondedor padrão sejam padrões mais comuns. De qualquer forma, as opções relevantes são os recursos e as opções, conforme são transmitidos a partir de from respond_with.

Nível da instância: respond_with

As opções aqui são aquelas que seriam passadas para renderizar ou redirecionar para o seu controlador, mas são incluídas apenas para cenários de sucesso. Para ações GET, essas seriam as chamadas de renderização; para outras ações, essas seriam as opções de redirecionamento. Provavelmente, a mais útil delas é a :locationopção, que pode ser usada para substituir esse caminho de redirecionamento, caso os argumentos para respond_with não sejam suficientes para criar a URL correta.

# 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, a gem dos respondedores não fornece apenas alguns módulos para substituir parte do comportamento padrão. Ele substitui o atendedor padrão por uma classe anônima que estende o atendedor padrão e fornece um método no nível da classe para misturar módulos personalizados a essa classe. O mais útil aqui é o respondedor de flash, que fornece um conjunto padrão de flashes, delegando a personalização ao sistema I18n, config/locales/en.ymlpor padrão.

Alguns exemplos de respondedores personalizados que usei em projetos anteriores incluem um respondedor que decorava automaticamente meus recursos e fornecia um conjunto padrão de títulos de página com uma interface para personalizar ou substituir facilmente o título da página.

Grupo
fonte
1
Eu acho que você quer dizer (no corpo da classe) self.responder =como apenas responder =irá atribuir a uma locais
horseyguy
Obrigado! A existência da locationopção era a informação que eu precisava!
JellicleCat
1
Essa explicação ainda é relevante para o Rails 4/5? Ouvi dizer que isso respond_withseria preterido, mas não consigo descobrir o porquê.
Arnlen
1
@Arnlen, o respond_with foi extraído como uma gema separada ' responders ' #
3155 Nick Roz
Observe que, para que os flashes config/locales/en.ymlfuncionem, você precisa responders :flashda parte superior do seu controlador.
bjnord