Rails: Як працює блок respo_to?


211

Я переглядаю посібник " Початок роботи з Rails" і переплутався з розділом 6.7. Після генерації ешафотів я знаходжу в моєму контролері такий автоматично створений блок:

def index
  @posts = Post.all

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

Я хотів би зрозуміти, як насправді працює блок respo_to. Який тип змінної є форматом? Чи є .html та .json методи об’єкта форматування? документація для

ActionController::MimeResponds::ClassMethods::respond_to

не відповідає на запитання.


Було б добре, якби я міг покластись на документацію для ActionController :: MimeResponds :: ClassMethods :: response_to, але api.rubyonrails.org, схоже, не любить прямих гіперпосилань ...
Cole

response_to приймає кінець дзвінка (наприклад, blah.html, blah.json тощо) і відповідає вказаному виду. Інші відповіді на відповіді можуть бути XML, CSV та багато інших, залежно від програми.
ScottJShea

5
Як це "відповідає вказаному перегляду?"
Коул

Я не думаю, що розширення (xml, html тощо) не відображається в представленні. Якщо ви виберете візуалізацію за замовчуванням ( format.html- немає аргументу), для вибору перегляду (очікується, що це HTML), використовуватимуть конвенції (на основі URL та HTTP дієслова). Тут відповідь (формат) доручає відображати URL-адреси, що закінчуються на .json, шляхом серіалізації до json, замість використання поглядів та умов.
Крейг Селесте

Відповіді:


189

Я новачок у Рубі і застряг у цьому самому коді. Частини, які я повісив, були трохи більш фундаментальними, ніж деякі відповіді, які я знайшов тут. Це може чи не допоможе комусь.

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

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

  • ResponderНе містить метод .htmlабо .json, але ми називаємо ці методи так чи інакше! Ця частина кинула мене за петлю.
  • У Рубі є функція під назвою method_missing. Якщо ви викликаєте метод, який не існує (наприклад, jsonабо html), method_missingнатомість Ruby викликає метод.

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, нам потрібен екземпляр класу, тому ми зобов'язані передати зворотний виклик, в який вони передають об'єкт, подібний методу. Для когось, хто кодується мовами, подібними до С протягом 20 років, для мене це дуже відстало і неінтуїтивно. Не те, що це погано! Але це багато чого з людьми з таким походженням, щоб обернутися головою, і я думаю, що це може бути те, що було після цього в ОП.

пс відзначити , що в RoR 4.2 respond_toекстрагують респондерів камінь.


Дякую Крейгу, що в цьому посиланні було також багато корисної інформації, я не зрозумів, наскільки це можливо method_missing, враховуючи, що ви можете передати це аргументами та блоком!
Адітя МП

2
Найкраща відповідь для пояснення використання method_missing () як механізму реєстрації в класі Відповідач! Я також дуже плутався з цим кодом.
Алан Евангеліста

1
Генератори respond_toрейкових лісових шатрів 6, схоже, виробляють код у контролерах, без дорогоцінного каменю, що реагує, у Gemfile. Можливо, дещо про respond_toвилучення в дорогоцінній камінь відповідачів було змінено?
Касим

106

Це блок коду Ruby, який використовує перевагу методу помічника Rails. Якщо ви ще не знайомі з блоками, ви побачите їх багато в Ruby.

respond_to- це помічник Rails, який приєднаний до класу Controller (а точніше, його суперкласу). Він посилається на відповідь, яка буде надіслана Перегляду (який переходить у браузер).

Блок у вашому прикладі - це форматування даних - передаючи параметр "формату" у блоці, що надсилається від контролера до перегляду щоразу, коли браузер робить запит на HTML або json.

Якщо ви знаходитесь на своїй локальній машині і у вас налаштований ешафот для пошти, ви можете перейти до, 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вгорі класу, ви можете оголосити всі формати, які ви хочете, щоб ваш контролер надсилав вашим переглядам.

Тоді, у методі контролера, все, що вам потрібно зробити, - це answer_with (@wever_object_you_have)

Це просто спрощує ваш код трохи більше, ніж те, що Rails автогенерує.

Якщо ви хочете дізнатися про внутрішню розробку цього ...

З того, що я розумію, 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 знати, що потрібно знайти "користувача" частковим і повторити всі об'єкти "користувачів":

Це повідомлення може бути корисним: http://archives.ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w- reply_with

Ви також можете ознайомитись з джерелом: https://github.com/rails/rails


1
Гарний наконечник на рейках3 способом. Я все ще намагаюся дістатись до нижньої частини блоку respo_to, і який аргумент блоку | формат | проходить.
Коул

4
Хороша відповідь, але не говорить нічого конкретного щодо змінної формату, що передається в блок. У наведеному прикладі є format.html і format.json - чи обидва вони передаються до respo_to, а потім response_to вирішує, що з ними робити?
Ентоні

коли був respond_toі respond_withпредставлений? Я використовую рейки 2.3.5, і я отримуюNoMethodError (undefined method respond_to)
грудня

10

Як я знаю, 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**>>

| Формат | частина - це аргумент, який очікує блок, тому всередині методу respo_to ми можемо використовувати це. Як?

Добре, якщо ви помітили, що ми передаємо блок із префіксом & у методі respo_to, і ми робимо це, щоб розглядати цей блок як Proc. Оскільки аргумент має ".xml", ".html", ми можемо використовувати це як методи, що викликаються.

Що ми в основному робимо в класі respo_to - це методи виклику ".html, .xml, .json" до екземпляра класу Responder.


1
Джерело для Respo_to в документах api відрізняється від джерела, який ви включили, і мене викидав. Ваш фрагмент робить мені зрозумілішим, що аргумент блоку формату передається об'єктом Responder. Документація Відповідача, здається, відповідає на питання, читаючи це зараз.
Коул

7

Я хотів би зрозуміти, як насправді працює блок respo_to. Який тип змінної є форматом? Чи є .html та .json методи об’єкта форматування?

Щоб зрозуміти, що formatтаке, спершу ви можете подивитися на джерело respond_to, але швидко ви побачите, що дійсно вам потрібно подивитися, це код для retrieve_response_from_mimes .

Звідси ви побачите, що блок, на який було передано respond_to(у вашому коді), насправді викликається та передається з екземпляром Collector (на який у блоці посилається format). Колектор в основному генерує методи (я вірю при запуску Rails) на основі того, про що знає рейки типу mime .

Отже, так, .htmlі .jsonє методи, визначені (під час виконання) на formatкласі Collector (aka ).


2

Метапрограмування за реєстрацією респондента (див. Відповідь 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 (або будь-який інший формат) зі свого рейкового сайту.

Рядок js призведе до надання / виконання файлу javascript /posts.js (або /posts.js.coffee). Я виявив, що це легкий спосіб створити сайт з підтримкою Ajax, використовуючи спливаючі вікна jQuery UI.


1

Який тип змінної є форматом?

Від Java POV формат - це реалізація анонімного інтерфейсу. Цей інтерфейс має один метод, названий для кожного типу mime. Коли ви посилаєтесь на один із цих методів (передаючи йому блок), тоді, якщо рейли вважають, що користувач хоче цього типу вмісту, він викличе ваш блок.

Зрозуміло, що цей анонімний клей-об'єкт насправді не реалізує інтерфейс - він динамічно вловлює виклики методу і спрацьовує, якщо це ім'я типу mime, про яке він знає.

Особисто я думаю, що це виглядає дивно: блок, який ти передаєш, виконується . Мені було б більше сенсу передавати хеш-формат міток і блоків. Але - ось, як це робиться в RoR, здається.


1

Це трохи застаріло, Райан Бігг чудово працює, пояснюючи це тут:

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

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


0

"Формат" - ваш тип відповіді. Наприклад, може бути json або html. Це формат результату, який отримає ваш відвідувач.


0

Є ще одне, про що слід пам’ятати - MIME.

Якщо вам потрібно використовувати тип MIME і він не підтримується за замовчуванням, ви можете зареєструвати власні обробники в config / inicijalizer / mime_types.rb:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.