Рендеринг представления

Цель типичного действия контроллера – выполнить рендеринг шаблона представления, то есть заполнить шаблон и передать результаты(обычно в форме HTML-документа) серверу, чтобы тот доставил их клиенту.
Как ни странно (по крайней мере, это может показаться немного странным, хотя и не лишенным логики), можно не определять действие контроллера, если существует шаблон с таким же именем, как у действия.

Можете проверить это в ручном режиме. Откройте файл app/controller/demo_controller.rb и удалите действие index, после чего файл будет выглядеть так:

class DemoController < ApplicationController
end

Не удаляя файл app/views/demo/index.rhtml, попробуйте выполнить с консоли то же упражнение, что и выше (вызвать метод Dispatcher.dispatch и т. д.). Результат получится точно таким же, как и раньше.

Кстати, не забывайте перезагружать консоль после внесения изменений – автоматически она не распознает, что код изменился. Самый простой способ перезагрузить консоль – просто ввести команду reload!. Но имейте в виду, что все существующие экземпляры ActiveRecord, на которые вы храните ссылки, также придется перезагрузить (с помощью их собственных методов reload). Иногда проще выйти из консоли и запустить ее заново.

Если сомневаетесь, рисуйте

Rails знает, что, получив запрос к действию index демонстрационного контроллера, он должен любой ценой вернуть что-то серверу. Раздействия index в файле контроллера нет, Rails пожимает плечами
и говорит: «Что ж, если бы действие index было, оно все равно оказалось бы пустым и я бы выполнил рендеринг шаблона index.rhtml. Так и сделаю это».
Однако даже на примере пустого действия контроллера кое-чему можно научиться. Вернемся к исходной версии демонстрационного контроллера:

class DemoController < ApplicationController
def index
end
end

Можно сделать вывод, что если в действии контроллера ничего другого не задано, то по умолчанию выполняется рендеринг шаблона, имя которого соответствует имени контроллера и действия. В данном случае это шаблон views/demo/index.rhtml.

Иными словами, в каждом действии контроллера имеется неявная команда render. Причем render – это самый настоящий метод. Предыдущий пример можно было бы переписать следующим образом:

def index
render :template => "demo/index"
end

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

Однако команда render – это не просто способ попросить Rails выполнить то, что он и так собирался сделать.

Явный рендеринг

Рендеринг шаблона – это как выбор рубашки. Если вам не нравится самая ближняя из висящих в шкафу – назовем ее рубашкой по умолчанию, – можно протянуть руку и достать другую.
Если действие контроллера не хочет рисовать шаблон по умолчанию, то может нарисовать любой другой, вызвав метод render явно. Доступен любой шаблон, находящийся в поддереве с корнем app/views (на самом деле, это не совсем точно – Доступен вообще любой шаблон в системе). Но зачем контроллеру может понадобиться выполнять рендеринг шаблона, отличного от шаблона по умолчанию? Причин несколько, и, познакомившись с некоторыми, мы сможем узнать о многих
полезных возможностях метода контроллера render.

Рендеринг шаблона другого действия

Типичный случай, когда нужно выполнять рендеринг совсем другого шаблона, – это повторный вывод формы, в которую пользователь ввел недопустимые данные. Обычно в такой ситуации выводят ту же самую форму с данными, введенными пользователем, а также дополнительную информацию об ошибках, чтобы пользователь мог их исправить и отправить форму еще раз.
Причина, по которой в этом случае приходится рисовать не шаблон по умолчанию, заключается в том, что действие обработки формы и действие вывода формы – чаще всего разные действия. Поэтому действию, которое обрабатывает форму, необходим способ повторно вывести исходный шаблон (форму), а не переходить к следующему экрану, как в случае корректно заполненной формы.

Вот практический пример:

class EventController < ActionController::Base
def new
# Это (пустое) действие выполняет рендеринг шаблона new.rhtml, который
# содержит форму для ввода информации о новом событии, оно по существу
# не нужно.
end
def create
# Этот метод обрабатывает данные из формы. Данные доступны через
# вложенный хеш params, являющийся значением ключа :event.
@event = Event.new(params[:event])
if @event.save
flash[:notice] = "Событие создано!"
redirect_to :controller => "main" # пока не обращайте внимания на
# эту строку
else
render :action => "new" # не выполняет метод new!
end
end
end

В случае ошибки – когда вызов @event.save не возвращает true – мы снова выполняем рендеринг шаблона new то есть файла new.rhtml. В предположении, что шаблон new.rhtml написан правильно, будет автоматически включена информация об ошибке, хранящаяся в новом (но не сохраненном) объекте @event класса Event.
Отметим, что сам шаблон new.rhtml не «знает», что он рисуется действием create, а не new. Он просто делает то, что требуется: выполняет подстановки на основе содержащихся в нем инструкций и переданных контроллером данных (в данном случае – объекта @event).

Рендеринг совершенно постороннего шаблона

Точно так же, как рисуется шаблон другого действия, выполняетсяи рендеринг любого хранящегося в системе шаблона. Для этого следуетвызвать метод render, передав в параметре :template или :file путьк нужному файлу шаблона.
Параметр :template должен содержать путь относительно корня деревашаблонов (app/views, если вы ничего не меняли, что было бы весьма необычно), а параметр :file – абсолютный путь в файловой системе.

Честно говоря, параметр :template редко используется при разработке приложений Rails.

render :template => "abuse/report" # рендеринг app/views/abuse/report.rhtml
render :file => "/railsapps/myweb/app/views/templates/common.rhtml"

Рендеринг подшаблона

Еще один случай – рендеринг подшаблона (partial template или просто partial). Вообще говоря, подшаблоны позволяют представить всю совокупность шаблонов в виде небольших файлов, избежав громоздкогокода и выделив модули, допускающие повторное использование.
Контроллер прибегает к рендерингу подшаблонов чаще всего для AJAX-вызовов, когда необходимо динамически обновлять участкиуже выведенной страницы.

Рендеринг встроенного шаблона

Иногда броузеру нужно послать результат трансляции какого-нибудь фрагмента шаблона, который слишком мал, чтобы оформлять его в виде отдельной части. Признаю, что такая практика спорна, так как является вопиющим нарушением принципа разделения ответственности между различными слоями MVC.
Один из часто встречающихся случаев употребления встроенного рендеринга и, пожалуй, единственная причина, по которой такая возможность вообще включена, – это использование помощников при обработке AJAX-запросов, например auto_complete_result

render :inline => „<%= auto_complete_result(@headings, 'name') %>"

Rails обрабатывает такой встроенный код точно так же, как если бы это был шаблон представления.

Рендеринг текста

Что если нужно отправить броузеру всего лишь простой текст, особенно когда речь идет об ответах на AJAX-запросы и некоторые запросы к веб-службам?

render :text => 'Данные приняты'

Рендеринг структурированных данных других типов

Команда render принимает ряд параметров, облегчающих возврат структурированных данных в таких форматах, как JSON или XML. При этом в ответе правильно выставляется заголовок content-type и другие характеристики.
:json
JSON1 – это небольшое подмножество языка JavaScript, применяемое в качестве простого формата обмена данными. Чаще всего он используется для отправки данных JavaScript-сценарию, который работает на стороне клиента в обогащенном веб-приложении и посылает серверу AJAX-запросы. В библиотеку ActiveRecord встроена поддержка для преобразования в формат JSON, что делает Rails идеальной платформой для возврата данных в этом формате, например:

render :json => @record.to_json

:xml

В ActiveRecord встроена также поддержка для преобразования в формат XML, например:

render :xml => @record.to_xml

Пустой рендеринг

Редко, но бывает, что не нужно рисовать вообще ничего (для обхода ошибки: в браузере Safari «ничего» на самом деле означает отправку браузеру одного пробела).

render :nothing => true, :status => 401 # Не авторизован

Стоит отметить, что, как показано в этом примере, render :nothing => true часто используется в сочетании с некоторым кодом состояния HTTP.

Параметры рендеринга

В большинстве обращений к методу render задаются дополнительные параметры. Ниже они перечислены в алфавитном порядке.

:content_type

С любым контентом, который циркулирует в Сети, ассоциирован тип MIME. Например, HTML-контенту соответствует тип text/html. Но иногда необходимо отправить клиенту данные в формате, отличном от
HTML. Rails не проверяет формат переданного идентификатора MIME, поэтому вы должны сами позаботиться о том, чтобы значение параметра :content_type было допустимым.

:layout

По умолчанию Rails придерживается определенных соглашений о шаблоне размещения, в который обертывается ваш ответ. Эти соглашения подробно рассматриваются в главе 10 «Компонент ActionView». Параметр :layout позволяет указать, нужен вам шаблон размещения или нет.

:status

В протоколе HTTP определено много стандартных кодов состояния1, описывающих вид ответа на запрос клиента. В большинстве типичных случаев Rails выбирает подходящий код автоматически, например 200 OK для успешно обработанного запроса.

КОММЕНТАРИИ