Spec-Zone.ru › Ruby on Rails 4.1

класс ActionController::Responder

Родитель:
Object

Отвечает за предоставление ресурса для различных запросов с разными типами контента, обычно в зависимости от HTTP-метода. Ответчик срабатывает при вызове respond_with. Простейший случай для изучения — это запрос GET:

class PeopleController < ApplicationController
  respond_to :html, :xml, :json

  def index
    @people = Person.all
    respond_with(@people)
  end
end

При поступлении запроса, например, для получения ответа в формате XML, происходят три шага:

1) the responder searches for a template at people/index.xml;

2) if the template is not available, it will invoke <code>#to_xml</code> on the given resource;

3) if the responder does not <code>respond_to :to_xml</code>, call <code>#to_format</code> on it.

Встроенная семантика HTTP-методов

Стандартный ответчик Rails содержит семантику для каждого HTTP-метода. В зависимости от типа контента, метода и состояния ресурса, он будет вести себя по-разному.

Используя стандартный ответчик Rails, запрос POST для создания объекта можно записать как:

def create
  @user = User.new(params[:user])
  flash[:notice] = 'User was successfully created.' if @user.save
  respond_with(@user)
end

Что точно так же, как:

def create
  @user = User.new(params[:user])

  respond_to do |format|
    if @user.save
      flash[:notice] = 'User was successfully created.'
      format.html { redirect_to(@user) }
      format.xml { render xml: @user, status: :created, location: @user }
    else
      format.html { render action: "new" }
      format.xml { render xml: @user.errors, status: :unprocessable_entity }
    end
  end
end

То же самое происходит для запросов PATCH/PUT и DELETE.

Вложенные ресурсы

Вы можете передавать вложенные ресурсы так же, как делаете в form_for и polymorphic_url. Представьте, что у проекта много задач. Действие create для контроллера TasksController будет выглядеть так:

def create
  @project = Project.find(params[:project_id])
  @task = @project.tasks.build(params[:task])
  flash[:notice] = 'Task was successfully created.' if @task.save
  respond_with(@project, @task)
end

Передача нескольких ресурсов гарантирует, что ответчик будет перенаправлять на project_task_url вместо task_url.

Для именованных и одиночных ресурсов требуется передать символ, как в полиморфных URL. Если у проекта один менеджер, который имеет много задач, вызов должен быть таким:

respond_with(@project, :manager, @task)

Обратите внимание, что если вы передаете массив, он будет обрабатываться как коллекция, поэтому следующее не эквивалентно:

respond_with [@project, :manager, @task]

Настраиваемые параметры

respond_with также позволяет передавать параметры, которые передаются в вызов render. Эти параметры применяются только для успешных сценариев. Например, вы можете сделать следующее в методе create выше:

def create
  @project = Project.find(params[:project_id])
  @task = @project.tasks.build(params[:task])
  flash[:notice] = 'Task was successfully created.' if @task.save
  respond_with(@project, @task, status: 201)
end

Это вернёт статус 201, если задача была успешно сохранена. В противном случае, он просто проигнорирует заданные параметры и вернёт статус 422 и ошибки ресурса. Вы также можете переопределить место перенаправления:

respond_with(@project, location: root_path)

Чтобы настроить сценарий ошибки, вы можете передать блок в respond_with:

def create
  @project = Project.find(params[:project_id])
  @task = @project.tasks.build(params[:task])
  respond_with(@project, @task, status: 201) do |format|
    if @task.save
      flash[:notice] = 'Task was successfully created.'
    else
      format.html { render "some_special_template" }
    end
  end
end

Использование respond_with с блоком следует той же синтаксической конструкции, что и respond_to.

Константы

DEFAULT_ACTIONS_FOR_VERBS

Атрибуты

controller[R]
format[R]
options[R]
request[R]
resource[R]
resources[R]

Публичные методы класса

call(*args) Показать исходный код

Инициализирует новый ответчик и вызывает соответствующий формат. Если формат не определен, вызов to_format.

# File actionpack/lib/action_controller/metal/responder.rb, line 150
def self.call(*args)
  new(*args).respond
end
new(controller, resources, options={}) Показать исходный код
# File actionpack/lib/action_controller/metal/responder.rb, line 129
def initialize(controller, resources, options={})
  @controller = controller
  @request = @controller.request
  @format = @controller.formats.first
  @resource = resources.last
  @resources = resources
  @options = options
  @action = options.delete(:action)
  @default_response = options.delete(:default_response)
end

Публичные методы экземпляра

respond() Показать исходный код

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

# File actionpack/lib/action_controller/metal/responder.rb, line 156
def respond
  method = "to_#{format}"
  respond_to?(method) ? send(method) : to_format
end
to_format() Показать исходный код

Все остальные форматы следуют процедуре, описанной ниже. Сначала мы пытаемся отобразить шаблон, если шаблон недоступен, мы проверяем, отвечает ли ресурс на :to_format и отображаем его.

# File actionpack/lib/action_controller/metal/responder.rb, line 179
def to_format
  if get? || !has_errors? || response_overridden?
    default_render
  else
    display_errors
  end
rescue ActionView::MissingTemplate => e
  api_behavior(e)
end
to_html() Показать исходный код

HTML-формат не отображает ресурс, он всегда пытается отобразить шаблон.

# File actionpack/lib/action_controller/metal/responder.rb, line 164
def to_html
  default_render
rescue ActionView::MissingTemplate => e
  navigation_behavior(e)
end
to_js() Показать исходный код

#to_js просто пытается отобразить шаблон. Если шаблон не найден, выдает ошибку.

# File actionpack/lib/action_controller/metal/responder.rb, line 171
def to_js
  default_render
end

Защищенные методы экземпляра

api_behavior(error) Показать исходный код

Это общее поведение для форматов, связанных с API, таких как :xml и :json.

# File actionpack/lib/action_controller/metal/responder.rb, line 203
def api_behavior(error)
  raise error unless resourceful?
  raise MissingRenderer.new(format) unless has_renderer?

  if get?
    display resource
  elsif post?
    display resource, :status => :created, :location => api_location
  else
    head :no_content
  end
end
api_location()
Псевдоним для: resource_location
default_action() Показать исходный код

По умолчанию отображает действие :edit для HTML-запросов с ошибками, если только глагол не был POST.

# File actionpack/lib/action_controller/metal/responder.rb, line 281
def default_action
  @action ||= DEFAULT_ACTIONS_FOR_VERBS[request.request_method_symbol]
end
default_render() Показать исходный код

Если был задан блок ответа, используйте его, иначе вызовите render в контроллере.

# File actionpack/lib/action_controller/metal/responder.rb, line 234
def default_render
  if @default_response
    @default_response.call(options)
  else
    controller.default_render(options)
  end
end
display(resource, given_options={}) Показать исходный код

Display — это просто сокращение для отображения ресурса с текущим форматом.

display @user, status: :ok

Для XML-запросов это эквивалентно:

render xml: @user, status: :ok

Используются также параметры, отправленные пользователем:

respond_with(@user, status: :created)
display(@user, status: :ok)

Результат:

render xml: @user, status: :created
# File actionpack/lib/action_controller/metal/responder.rb, line 259
def display(resource, given_options={})
  controller.render given_options.merge!(options).merge!(format => resource)
end
display_errors() Показать исходный код
# File actionpack/lib/action_controller/metal/responder.rb, line 263
def display_errors
  controller.render format => resource_errors, :status => :unprocessable_entity
end
has_errors?() Показать исходный код

Проверить, есть ли у ресурса ошибки.

# File actionpack/lib/action_controller/metal/responder.rb, line 269
def has_errors?
  resource.respond_to?(:errors) && !resource.errors.empty?
end
has_renderer?() Показать исходный код

Проверить, доступен ли необходимый Renderer

# File actionpack/lib/action_controller/metal/responder.rb, line 274
def has_renderer?
  Renderers::RENDERERS.include?(format)
end
json_resource_errors() Показать исходный код
# File actionpack/lib/action_controller/metal/responder.rb, line 289
def json_resource_errors
  {:errors => resource.errors}
end
navigation_behavior(error) Показать исходный код

Это общее поведение для форматов, связанных с просмотром, таких как :html, :iphone и так далее.

# File actionpack/lib/action_controller/metal/responder.rb, line 192
def navigation_behavior(error)
  if get?
    raise error
  elsif has_errors? && default_action
    render :action => default_action
  else
    redirect_to navigation_location
  end
end
navigation_location()
Псевдоним для: resource_location
resource_errors() Показать исходный код
# File actionpack/lib/action_controller/metal/responder.rb, line 285
def resource_errors
  respond_to?("#{format}_resource_errors", true) ? send("#{format}_resource_errors") : resource.errors
end
resource_location() Показать исходный код

Возвращает местоположение ресурса, извлекая его из параметров или возвращая массив ресурсов.

# File actionpack/lib/action_controller/metal/responder.rb, line 225
def resource_location
  options[:location] || resources
end
Также имеет псевдонимы: navigation_location, api_location
resourceful?() Показать исходный код

Проверяет, отвечает ли ресурс на текущий формат или нет.

# File actionpack/lib/action_controller/metal/responder.rb, line 218
def resourceful?
  resource.respond_to?("to_#{format}")
end
response_overridden?() Показать исходный код
# File actionpack/lib/action_controller/metal/responder.rb, line 293
def response_overridden?
  @default_response.present?
end

© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API