Spec-Zone.ru › Ruby on Rails 5.0

модуль ActionView::Layouts

Включенные модули:
ActionView::Rendering

Макеты инвертируют общую схему включения общих заголовков и подвалов во многих шаблонах, чтобы изолировать изменения в повторяемых настройках. Схема включения имеет страницы, которые выглядят так:

<%= 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», потому что он установил макет в nil, сбросив конфигурацию родителя.

  • 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".

Установка макета в 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 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» вместо него.

Общедоступные методы экземпляров

action_has_layout?() Показать исходный код
# File actionview/lib/action_view/layouts.rb, line 364
def action_has_layout?
  @_action_has_layout
end

Управляет тем, должно ли действие рендериться с помощью макета. Если вы хотите отключить какие-либо layout настройки для текущего действия, чтобы оно рендерилось без макета, то либо переопределите этот метод в своём контроллере, чтобы он возвращал false для этого действия, либо установите атрибут action_has_layout в false перед рендерингом.

© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API