Rails respons_with: как это работает?

#ruby-on-rails #ruby-on-rails-3

#ruby-on-rails #ruby-on-rails-3

Вопрос:

Я тут и там читал о том, какой классный respond_with метод в Rails 3. Но я даже не могу найти ссылку на это ни в Rails API, ни при поиске в источнике. Может кто-нибудь объяснить мне, как это работает (какие опции вы можете использовать и т.д.), Или указать мне место, где это фактически реализовано, чтобы я мог самостоятельно ознакомиться с кодом?

Ответ №1:

Обновление для Rails 4.2

#respond_with и ::respond_to (n.b. метод класса) больше не являются частью Rails. Они были перенесены в gem сторонних ответчиков начиная с Rails 4.2 (примечания к выпуску / фиксация от августа 2014). Хотя respond-ы не включены в Rails по умолчанию, они зависят от Devise и, следовательно, доступны во многих приложениях Rails.

#respond_to Метод экземпляра, однако, все еще является частью Rails (5.2rc1 на момент написания этой статьи).

Официальная документация Rails API для ActionController::MimeResponds объясняет, как #respond_to это работает. Оригинальные Rails содержат комментарии к документации для #respond_with и ::respond_to все еще можно найти в исходном коде responsers gem.


Оригинальный ответ

Код для ответчиков основан на классе и модуле. MimeResponds, который включен в ActionController::Base, класс, от которого вы ApplicationController наследуете. Тогда есть ActionController::Responder, который обеспечивает поведение по умолчанию при использовании respond_with .


По умолчанию единственное поведение, которое rails предоставляет в ответе, — это неявная попытка отобразить шаблон с именем, соответствующим действию. Все, что выходит за рамки этого, требует дополнительных инструкций внутри действия или пользовательского вызова response_to с блоком для обработки ответов в нескольких форматах.

Поскольку большинство контроллеров используют довольно распространенный шаблон настройки, ответчики обеспечивают дополнительный уровень абстракции, вводя поведение по умолчанию. Действия чтения, вызывающие to_xml / to_json для определенных форматов, и действия мутатора, обеспечивающие то же самое, а также перенаправления для успешных действий мутатора.


Есть несколько возможностей настроить поведение ответчиков, от тонких настроек до полного переопределения или расширения поведения.

Уровень класса: respond_to

Здесь вы указываете форматы, которые должен обрабатывать ответчик. Форматы могут быть настроены в отношении того, к каким действиям они будут применяться. Каждый формат может быть указан с помощью отдельных вызовов, что позволяет полностью настраивать действия для каждого формата.

 # 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]
  

Уровень класса: responder

Это атрибут класса, который содержит ответчик. Это может быть все, что отвечает на вызов, что означает, что вы можете использовать proc / lambda или класс, который отвечает на вызов. Другой альтернативой является добавление одного или модулей к существующему ответчику для перегрузки существующих методов, улучшая поведение по умолчанию.

 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
  

Хотя могут быть некоторые интересные варианты использования edge, более вероятно, что расширение или смешивание модулей в ответчике по умолчанию было бы более распространенными шаблонами. В любом случае, релевантными параметрами являются ресурсы и опции, поскольку они передаются из от respons_with .

Уровень экземпляра: respond_with

Здесь указаны параметры, которые будут переданы для render или redirect_to в вашем контроллере, но они включены только для сценариев успеха. Для действий GET это были бы вызовы визуализации, для других действий это были бы опции для перенаправления. Вероятно, наиболее полезной из них является :location опция, которая может быть использована для переопределения этого пути перенаправления в случае, если аргументов для response_with недостаточно для создания правильного URL.

 # 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'))
  

В качестве альтернативы, gem ответчиков не только предоставляет некоторые модули для переопределения некоторого поведения по умолчанию. Он переопределяет ответчик по умолчанию анонимным классом, который расширяет ответчик по умолчанию, и предоставляет метод уровня класса для смешивания пользовательских модулей с этим классом. Наиболее полезным здесь является flash responser, который предоставляет набор вспышек по умолчанию, по умолчанию делегируя настройку системе I18n. config/locales/en.yml

Некоторые примеры пользовательских ответчиков, которые я использовал в предыдущих проектах, включают ответчик, который автоматически оформлял мои ресурсы и предоставлял набор заголовков страниц по умолчанию с интерфейсом для простой настройки или переопределения заголовка страницы.

Комментарии:

1. Я думаю, вы имеете в виду (в теле класса), self.responder = поскольку просто responder = присвоит локальному

2. Спасибо! Существование location опции было той информацией, в которой я нуждался!

3. Это объяснение все еще актуально для Rails 4/5? Я слышал, что это respond_with устарело, но мне не удается выяснить, почему.

4. @Arnlen, respons_with был извлечен как отдельный gem ‘ респонденты

5. Обратите внимание, что для того, чтобы вспышки в вашем config/locales/en.yml работали, вам нужно responders :flash в верхней части вашего контроллера.