модуль ActionView::Layouts
Шаблоны представления Action View
Layouts отменяют общую схему включения общих заголовков и подвалов во многих шаблонах, чтобы изолировать изменения в повторяющихся настройках. Схема включения имеет страницы, которые выглядят так:
<%= render "application/header" %> Hello World <%= render "application/footer" %>
Этот подход является приемлемым способом изоляции общих структур от изменяемого контента, но он громоздкий, и если вам когда-либо захочется изменить структуру этих двух включений, вам нужно будет изменить все шаблоны.
С помощью шаблонов вы можете перевернуть его и дать общей структуре знать, где вставлять изменяемый контент. Это означает, что заголовок и подвал упоминаются только в одном месте, например так:
// The header part of this layout <%= yield %> // The footer part of this layout
А затем у вас есть страницы с контентом, которые выглядят так:
hello world
Во время рендеринга страница с контентом вычисляется и затем вставляется в шаблон, примерно так:
// The header part of this layout hello world // The footer part of this layout
Доступ к общим переменным
Layouts имеют доступ к переменным, указанным на страницах с контентом, и наоборот. Это позволяет вам иметь шаблоны с ссылками, которые не будут материализоваться до времени рендеринга:
<h1><%= @page_title %></h1> <%= yield %>
…и страницы с контентом, которые удовлетворяют этим ссылкам во время рендеринга:
<% @page_title = "Welcome" %> Off-world colonies offers you a chance to start a new life
Результат после рендеринга:
<h1>Welcome</h1> Off-world colonies offers you a chance to start a new life
Назначение шаблона
Вы можете либо указать шаблон декларативно (используя метод класса layout) , либо дать ему то же имя, что и у вашего контроллера, и поместить его в app/views/layouts. Если подкласс не имеет заданного шаблона, он наследует его шаблон с использованием обычного наследования Ruby.
Например, если у вас есть PostsController и шаблон с именем app/views/layouts/posts.html.erb, этот шаблон будет использоваться для всех действий в PostsController и контроллерах, унаследованных от PostsController.
Если вы используете модуль, например Weblog::PostsController, вам понадобится шаблон с именем app/views/layouts/weblog/posts.html.erb.
Поскольку все ваши контроллеры унаследованы от ApplicationController, они будут использовать app/views/layouts/application.html.erb , если другой шаблон не указан или не предоставлен.
Примеры наследования
class BankController < ActionController::Base # bank.html.erb exists class ExchangeController < BankController # exchange.html.erb exists class CurrencyController < BankController class InformationController < BankController layout "information" class TellerController < InformationController # teller.html.erb exists class EmployeeController < InformationController # employee.html.erb exists layout nil class VaultController < BankController layout :access_level_layout class TillController < BankController layout false
В этих примерах у нас есть три сценария неявного поиска:
-
BankControllerиспользует шаблон «bank». -
ExchangeControllerиспользует шаблон «exchange». -
CurrencyControllerнаследует шаблон от BankController.
Однако, когда шаблон явно задан, явно заданный шаблон имеет приоритет:
-
InformationControllerиспользует шаблон «information», который был явно задан. -
TellerControllerтакже использует шаблон «information», потому что родительский класс явно его задал. -
EmployeeControllerиспользует шаблон «employee», потому что он установил шаблон наnil, сбросив конфигурацию родителя. -
VaultControllerдинамически выбирает шаблон, вызывая методaccess_level_layout. -
TillControllerвообще не использует шаблон.
Типы шаблонов
Layouts — это просто обычные шаблоны, но имя этого шаблона не нужно указывать статически. Иногда вы хотите изменять шаблоны в зависимости от информации во время выполнения, например, от того, вошел ли пользователь в систему или нет. Это можно сделать, указав ссылку на метод в виде символа или используя встроенный метод (как лямбда-выражение).
Ссылка на метод — предпочтительный подход для переменных шаблонов и используется так:
class WeblogController < ActionController::Base
layout :writers_and_readers
def index
# fetching posts
end
private
def writers_and_readers
logged_in? ? "writer_layout" : "reader_layout"
end
end
Теперь при обработке нового запроса для действия index шаблон будет отличаться в зависимости от того, вошел ли пользователь в систему или нет.
Если вы хотите использовать встроенный метод, например лямбда-выражение, сделайте что-то вроде этого:
class WeblogController < ActionController::Base
layout proc { |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
end
Если аргумент не передаётся лямбда-выражению, оно всё равно оценивается в контексте текущего контроллера.
class WeblogController < ActionController::Base
layout proc { logged_in? ? "writer_layout" : "reader_layout" }
end
Конечно, наиболее распространённый способ указания шаблона по-прежнему заключается в простом указании имени шаблона:
class WeblogController < ActionController::Base layout "weblog_standard" end
Шаблон будет всегда искаться в папке app/views/layouts/. Но вы также можете указать папку layouts напрямую. layout "layouts/demo" эквивалентно layout "demo".
Указание шаблона nil заставляет его искать в файловой системе и переходить к поведению родителя, если он не существует. Указание nil полезно для повторного включения поиска шаблонов, перезаписывая предыдущую конфигурацию, установленную в родителе:
class ApplicationController < ActionController::Base layout "application" end class PostsController < ApplicationController # Will use "application" layout end class CommentsController < ApplicationController # Will search for "comments" layout and fall back to "application" layout layout nil end
Условные шаблоны
Если у вас есть шаблон, который по умолчанию применяется ко всем действиям контроллера, у вас всё ещё есть возможность отобразить данное действие или набор действий без шаблона или ограничить шаблон только одним действием или набором действий. Опции :only и :except могут быть переданы в вызов шаблона. Например:
class WeblogController < ActionController::Base layout "weblog_standard", except: :rss # ... end
Это назначит «weblog_standard» в качестве шаблона WeblogController для всех действий, кроме действия rss, которое будет отображено непосредственно без обертывания шаблона вокруг отображаемого представления.
И условие :only, и условие :except могут принимать произвольное количество ссылок на методы, поэтому except: [ :rss, :text_only ] допустимо, так же как и except: :rss.
Использование другого шаблона в вызове рендеринга действия
Если большинство ваших действий используют один и тот же шаблон, имеет смысл определить шаблон для всего контроллера, как описано выше. Иногда у вас будут исключения, когда одно действие хочет использовать другой шаблон, чем остальная часть контроллера. Вы можете сделать это, передав опцию :layout в вызов render. Например:
class WeblogController < ActionController::Base
layout "weblog_standard"
def help
render action: "help", layout: "help"
end
end
Это переопределит шаблон «weblog_standard» для всего контроллера и отобразит действие help с шаблоном «help» вместо него.
Публичные методы экземпляра
# File actionview/lib/action_view/layouts.rb, line 372 def action_has_layout? @_action_has_layout end
Управляет тем, должно ли действие отображаться с помощью шаблона. Если вы хотите отключить любые настройки layout для текущего действия, чтобы оно отображалось без шаблона, то либо переопределите этот метод в своём контроллере, чтобы он возвращал false для этого действия, либо установите атрибут action_has_layout в значение false перед рендерингом.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.