модуль ActionView::Layouts
Макеты изменяют обычную схему включения общих заголовков и футеров во многих шаблонах, чтобы изолировать изменения в повторяющихся настройках. Шаблоны включают страницы, которые выглядят так:
<%= render "shared/header" %> Hello World <%= render "shared/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
Доступ к общим переменным
Макеты имеют доступ к переменным, указанным на страницах содержимого, и наоборот. Это позволяет иметь макеты со ссылками, которые не будут материализоваться до момента отрисовки:
<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
Назначение макета
Вы можете указать макет декларативно (используя метод класса макета) или дать ему то же имя, что и у вашего контроллера, и поместить его в 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», потому что он установил макет в null, сбросив конфигурацию родителя.
-
VaultController динамически выбирает макет, вызывая метод
access_level_layout. -
TillController вообще не использует макет.
Типы макетов
Макеты — это по сути обычные шаблоны, но имя этого шаблона не нужно указывать статически. Иногда вы хотите чередовать макеты в зависимости от информации во время выполнения, например, от того, вошел ли кто-то в систему или нет. Это можно сделать, указав ссылку на метод как символ или используя встроенный метод (как процедуру).
Ссылка на метод — предпочтительный подход к переменным макетам и используется следующим образом:
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".
Установка макета в null принудительно заставляет его быть найденным в файловой системе и возвращается к поведению родителя, если он отсутствует. Установка в null полезна для повторного включения поиска шаблонов, переопределяя предыдущую конфигурацию, установленную в родителе:
class ApplicationController < ActionController::Base layout "application" end class PostsController < ApplicationController # Will use "application" layout end class CommentsController < ApplicationController # Will search for "comments" layout and fallback "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» вместо него.
Публичные методы экземпляра
Управляет тем, должно ли действие отображаться с использованием макета. Если вы хотите отключить любые layout настройки для текущего действия, чтобы оно отображалось без макета, то либо переопределите этот метод в своем контроллере, чтобы он возвращал false для этого действия, либо установите атрибут action_has_layout в false перед отображением.
# File actionview/lib/action_view/layouts.rb, line 364 def action_has_layout? @_action_has_layout end
© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.