Rails: Как работает блок response_to? - PullRequest
202 голосов
/ 29 февраля 2012

Я изучаю руководство Getting Started with Rails и запутался в разделе 6.7.После генерации скаффолда я нахожу следующий автоматически сгенерированный блок в моем контроллере:

def index
  @posts = Post.all

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

Я хотел бы понять, как на самом деле работает блок response_to.Какой тип переменной является форматом?Являются ли методы .html и .json объекта формата?Документация для ActionController::MimeResponds::ClassMethods::respond_to не отвечает на вопрос.

Ответы [ 9 ]

177 голосов
/ 15 ноября 2012

Я новичок в Ruby и застрял в этом же коде.Части, на которые я повесил трубку, были немного более фундаментальными, чем некоторые ответы, которые я нашел здесь.Это может или не может помочь кому-то.

  • respond_to - это метод в суперклассе ActionController.
  • , который принимает блок, который похож на делегат.Блок имеет значение от do до end, с |format| в качестве аргумента блока.
  • response_to выполняет ваш блок, передавая ответчик в аргумент format.

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

  • Responder НЕ содержит метода для .html или .json, но мы вызываем эти методы в любом случае!Эта часть заставила меня задуматься.
  • В Ruby есть функция под названием method_missing.Если вы вызываете метод, который не существует (например, json или html), Ruby вместо этого вызывает метод method_missing.

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

  • Класс Responder использует свой method_missing в качестве своего рода регистрации.Когда мы вызываем 'json', мы говорим ему отвечать на запросы с расширением .json путем сериализации в json.Нам нужно вызвать html без аргументов, чтобы сказать, что он должен обрабатывать .html-запросы способом по умолчанию (с использованием соглашений и представлений).

Это можно записать так (используя 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)

Эта часть меня запутала.Я все еще нахожу это не интуитивным.Руби, кажется, использует эту технику совсем немного.Весь класс (responder) становится реализацией метода.Чтобы использовать method_missing, нам нужен экземпляр класса, поэтому мы обязаны передать обратный вызов, в который они передают объект, подобный методу.Для кого-то, кто программировал на C-подобных языках в течение 20 лет, это очень отсталое и не очень понятное для меня.Не то чтобы это плохо!Но это то, что многим людям с подобным происхождением нужно разбираться, и я думаю, что это может быть тем, что было после ОП.

ps обратите внимание, что в RoR 4.2 respond_to было извлечено в респонденты драгоценный камень.

100 голосов
/ 29 февраля 2012

Это блок кода Ruby, который использует вспомогательный метод Rails.Если вы еще не знакомы с блоками, вы часто их увидите в Ruby.

respond_to - это вспомогательный метод Rails, который присоединен к классу Controller (точнее, к его суперклассу).Он ссылается на ответ, который будет отправлен в представление (которое отправляется в браузер).

Блок в вашем примере - это форматирование данных - путем передачи параметра "format" в блоке - чтобы бытьотправляется с контроллера на представление всякий раз, когда браузер запрашивает данные html или json.

Если вы находитесь на локальном компьютере и у вас настроен эшафот Post, вы можете перейти на http://localhost:3000/posts и выувидит все ваши сообщения в формате HTML.Но если вы введете это: http://localhost:3000/posts.json, то вы увидите все свои сообщения в объекте json, отправленном с сервера.

Это очень удобно для создания тяжелых приложений на javascript, которые должны передавать json назад и вперед с сервера.Если вы хотите, вы можете легко создать json api на вашем рельсе, и передать только одно представление - как представление индекса вашего контроллера Post.Тогда вы можете использовать библиотеку javascript, такую ​​как Jquery или Backbone (или обе), чтобы манипулировать данными и создавать свой собственный интерфейс.Они называются асинхронными пользовательскими интерфейсами , и они становятся действительно популярными (Gmail - один из них).Они очень быстрые и дают конечному пользователю более настольный опыт в Интернете.Конечно, это только одно из преимуществ форматирования ваших данных.

В Rails 3 это можно записать следующим образом:

    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

Поставив respond_to :html, :xml, :json на вершину класса, вы можете объявить все форматы, которые вы хотите, чтобы ваш контроллер отправлял в ваши представления.

Затем, в методе контроллера, все, что вам нужно сделать, это response_with (@whwhat_object_you_have)

Это простоУпрощает ваш код немного больше, чем то, что автоматически генерирует Rails.

Если вы хотите узнать о внутренней работе этого ...

Из того, что я понимаюRails анализирует объекты, чтобы определить, каким будет фактический формат.Значение переменных 'format' основано на этом самоанализе.Rails может многое сделать с небольшим количеством информации.Вы будете удивлены, насколько далеко зайдет простой @post или: post.

Например, если бы у меня был частичный файл _user.html.erb, который выглядел так:

_user.html.erb

<li>    
    <%= link_to user.name, user %>
</li>

Затем, только это в моем представлении индекса позволит Rails знать, что ему нужно найти частичную часть «пользователей» и выполнить итерацию по всем «пользователям».объекты:

index.html.erb

 <ul class="users">
   <%= render @users %>     
 </ul>

сообщит Rails, что ему нужно найти частичную часть 'user' и выполнить итерацию по всем 'users''objects:

Вы можете найти этот пост полезным: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with

Вы также можете просмотреть источник: https://github.com/rails/rails

10 голосов
/ 29 февраля 2012

Из того, что я знаю, response_to - это метод, присоединенный к ActionController, так что вы можете использовать его в каждом контроллере, потому что все они наследуются от ActionController. Вот метод Rails response_to:

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

Вы передаете это блок , как я показываю здесь:

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

Часть | format | - это аргумент, который ожидает блок, поэтому внутри метода response_to мы можем это использовать. Как?

Что ж, если вы заметили, мы передаем блок с префиксом & в методе response_to, и мы делаем это для обработки этого блока как Proc. Поскольку аргумент имеет «.xml», «.html», мы можем использовать его как вызываемые методы.

Что мы в основном делаем в классе response_to, так это вызываем методы ".html, .xml, .json" для экземпляра класса Responder.

7 голосов
/ 29 февраля 2012

Я бы хотел понять, как на самом деле работает блок response_to.Какой тип переменной является форматом?Являются ли методы .html и .json объекта формата?

Чтобы понять, что такое format, вы можете сначала взглянуть на источник для respond_to, но быстро вы обнаружите, чтона самом деле вам нужно взглянуть на код retrieve_response_from_mimes .

Отсюда вы увидите, что блок, который был передан в respond_to (в вашем коде), на самом делевызывается и передается с экземпляром Collector (на который в блоке ссылаются как format).Collector в основном генерирует методы (я полагаю, при запуске Rails) на основе того, о чем mime-типы rails знают.

Итак, да, .html и .json являются методами, определенными (во время выполнения) в классе Collector (он же format).

2 голосов
/ 28 августа 2013

Мета-программирование за регистрацией респондента (см. Ответ Parched Squid) также позволяет вам делать изящные вещи вроде этого:

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

Строка csv будет вызывать to_csv для каждого сообщения при посещении /posts.csv. Это позволяет легко экспортировать данные в формате CSV (или в любом другом формате) с вашего сайта rails.

Строка js будет вызывать / выполнять файл javascript /posts.js (или /posts.js.coffee). Я обнаружил, что это простой способ создания сайта с поддержкой Ajax с использованием всплывающих окон jQuery UI.

1 голос
/ 15 марта 2018

Есть еще одна вещь, о которой вы должны знать - MIME.

Если вам нужно использовать тип MIME, и он не поддерживается по умолчанию, вы можете зарегистрировать свои собственные обработчики в config / initializer /mime_types.rb:

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

1 голос
/ 06 января 2014

Какой тип переменной является форматом?

В java POV формат представляет собой реализацию анонимного интерфейса.Этот интерфейс имеет один метод, названный для каждого типа MIME.Когда вы вызываете один из этих методов (передавая ему блок), тогда, если rails чувствует, что пользователь хочет этот тип контента, тогда он вызовет ваш блок.

Конечно, поворот заключается в том, что этот анонимный клейобъект на самом деле не реализует интерфейс - он динамически перехватывает вызовы метода и работает, если его имя типа mime, о котором он знает.

Лично я думаю, что это выглядит странно: блок, который вы передаетев выполнено .Для меня было бы больше смысла передавать в хэш меток формата и блоков.Но, похоже, именно так все и сделано в RoR.

1 голос
/ 27 октября 2012

Это немного устарело, Райан Бигг делает большую работу, объясняя это здесь:

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

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

0 голосов
/ 05 июля 2014

«Формат» - это ваш тип ответа.Например, может быть json или html.Это формат вывода, который получит ваш посетитель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...