Почему все строки в макете указываются косвенно из файла ресурсов

Обновлено: 21.11.2024

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

Предварительные требования: Базовая компьютерная грамотность. Базовое понимание того, что такое веб-сервер.
Цель: Понимать взаимодействие клиент-сервер на динамическом веб-сайте и в частности, какие операции должны выполняться серверным кодом.

В обсуждении нет реального кода, потому что мы еще не выбрали веб-фреймворк для написания нашего кода! Тем не менее, это обсуждение по-прежнему очень актуально, потому что описанное поведение должно быть реализовано вашим кодом на стороне сервера, независимо от того, какой язык программирования или веб-фреймворк вы выберете.

Этот запрос включает:

Веб-серверы ожидают сообщений с запросами клиентов, обрабатывают их, когда они приходят, и отвечают веб-браузеру ответным сообщением HTTP. Ответ содержит код состояния ответа HTTP, указывающий, был ли запрос выполнен успешно (например, «200 OK» для успеха, «404 Not Found», если ресурс не может быть найден, «403 Forbidden», если пользователь не авторизован для просмотра ресурс и др.). Тело успешного ответа на запрос GET будет содержать запрошенный ресурс.

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

Пример запроса/ответа GET

Вы можете сделать простой запрос GET, щелкнув ссылку или выполнив поиск на сайте (например, на главной странице поисковой системы). Например, HTTP-запрос, который отправляется, когда вы выполняете поиск в MDN по термину «обзор клиент-сервер», будет очень похож на текст, показанный ниже (он не будет идентичен, поскольку части сообщения зависят от вашего браузера/настройки). ).

Примечание. Формат сообщений HTTP определяется "веб-стандартом" (RFC7230). Вам не нужно знать такой уровень детализации, но, по крайней мере, теперь вы знаете, откуда все это взялось!

Запрос

Каждая строка запроса содержит информацию о нем. Первая часть называется заголовком и содержит полезную информацию о запросе, точно так же, как заголовок HTML содержит полезную информацию о HTML-документе (но не само фактическое содержимое, которое находится в теле):

Первая и вторая строки содержат большую часть информации, о которой мы говорили выше:

Остальные строки содержат информацию об используемом браузере и типах ответов, которые он может обрабатывать. Например, здесь вы можете увидеть, что:

Ответ

Первая часть ответа на этот запрос показана ниже. Заголовок содержит следующую информацию:

  • Первая строка содержит код ответа 200 OK , который говорит нам об успешном выполнении запроса.
  • Мы видим, что ответ имеет формат text/html ( Content-Type ).
  • Мы также видим, что он использует набор символов UTF-8 ( Content-Type: text/html; charset=utf-8 ).
  • Заголовок также сообщает нам, насколько он велик ( Content-Length: 41823 ).

В конце сообщения мы видим содержимое тела, которое содержит фактический HTML-код, возвращаемый запросом.

Остальная часть заголовка ответа включает информацию об ответе (например, когда он был сгенерирован), сервере и о том, как он ожидает, что браузер будет обрабатывать страницу (например, строка X-Frame-Options: DENY сообщает браузеру, что чтобы разрешить встраивание этой страницы в другой сайт).

Пример запроса/ответа POST

Запрос

Основное отличие состоит в том, что URL не имеет параметров. Как видите, информация из формы закодирована в теле запроса (например, полное имя нового пользователя задается с помощью: &user-fullname=Hamish+Willee ).

Ответ

Статические сайты

Статический сайт – это сайт, который возвращает одно и то же жестко запрограммированное содержимое с сервера при каждом запросе определенного ресурса. Так, например, если у вас есть страница о продукте в /static/myproduct1.html , эта же страница будет возвращена каждому пользователю. Если вы добавите на свой сайт другой похожий продукт, вам нужно будет добавить еще одну страницу (например, myproduct2.html) и так далее. Это может стать действительно неэффективным — что произойдет, когда вы доберетесь до тысяч страниц продукта? Вы будете повторять много кода на каждой странице (базовый шаблон страницы, структура и т. д.), и если вы захотите что-то изменить в структуре страницы — например, добавить новый раздел «сопутствующие товары», — тогда вы приходится менять каждую страницу по отдельности.

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

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

Когда пользователь хочет перейти на страницу, браузер отправляет HTTP-запрос GET с указанием URL-адреса его HTML-страницы. Сервер извлекает запрошенный документ из своей файловой системы и возвращает ответ HTTP, содержащий документ и код состояния ответа HTTP «200 OK» (указывающий на успех). Сервер может вернуть другой код состояния, например "404 Not Found", если файл отсутствует на сервере, или "301 Moved Permanently", если файл существует, но был перенаправлен в другое место.

Понимание того, как работают статические сайты, тем не менее полезно при изучении серверного программирования, поскольку динамические сайты обрабатывают запросы на статические файлы (CSS, JavaScript, статические изображения и т. д.) точно так же.

Динамические сайты

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

Использование шаблонов HTML упрощает изменение структуры HTML, поскольку это нужно делать только в одном месте, в одном шаблоне, а не на тысячах статических страниц.

Структура динамического запроса

В этом разделе представлен пошаговый обзор «динамического» цикла HTTP-запросов и ответов, основанный на том, что мы рассмотрели в предыдущей статье, с более подробным описанием. Чтобы «сохранить реальность», мы будем использовать контекст веб-сайта менеджера спортивной команды, где тренер может выбрать название своей команды и размер команды в HTML-форме и получить предложенный «лучший состав» для своей следующей игры.

После того, как тренер отправит форму с названием команды и количеством игроков, последовательность операций следующая:

  1. Веб-браузер создает HTTP-запрос GET на сервер, используя базовый URL-адрес ресурса ( /best ) и кодируя номер команды и игрока либо как параметры URL-адреса (например, /best?team=my_team_name&show=11), либо как его часть. шаблона URL (например, /best/my_team_name/11/ ). Запрос GET используется, поскольку запрос только извлекает данные (не изменяет данные).
  2. Веб-сервер определяет, что запрос является "динамическим", и перенаправляет его в веб-приложение для обработки (веб-сервер определяет, как обрабатывать разные URL-адреса на основе шаблона). правила сопоставления, определенные в его конфигурации).
  3. Веб-приложение определяет, что намерение запроса состоит в том, чтобы получить «список лучших команд» на основе URL-адреса ( /best/ ), и находит необходимые название команды и количество игроков из URL. Затем веб-приложение получает необходимую информацию из базы данных (используя дополнительные «внутренние» параметры, чтобы определить, какие игроки являются «лучшими», и, возможно, также получая идентификатор вошедшего в систему тренера с клиентской стороны). куки).
  4. Веб-приложение динамически создает HTML-страницу, помещая данные (из базы данных) в заполнители внутри шаблона HTML.
  5. Веб-приложение возвращает сгенерированный HTML-код в веб-браузер (через веб-сервер) вместе с кодом состояния HTTP 200 ("успешно"). Если что-то препятствует возврату HTML, веб-приложение вернет другой код, например "404", чтобы указать, что команда не существует.
  6. Затем веб-браузер начнет обрабатывать возвращенный HTML-код, отправляя отдельные запросы для получения любых других файлов CSS или JavaScript, на которые он ссылается (см. шаг 7).
  7. Веб-сервер загружает статические файлы из файловой системы и возвращает их непосредственно в браузер (опять же, правильная обработка файлов основана на правилах конфигурации и сопоставлении шаблонов URL-адресов).

Выполнение другой работы

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

Возврат чего-либо, отличного от HTML

Код веб-сайта на стороне сервера не должен возвращать фрагменты HTML или файлы в ответе.Вместо этого он может динамически создавать и возвращать другие типы файлов (текст, PDF, CSV и т. д.) или даже данные (JSON, XML и т. д.).

Идея возвращать данные в веб-браузер, чтобы он мог динамически обновлять свой собственный контент (AJAX), существует уже довольно давно. В последнее время стали популярными «одностраничные приложения», когда весь веб-сайт написан с помощью одного HTML-файла, который динамически обновляется при необходимости. Веб-сайты, созданные с использованием этого стиля приложений, требуют больших вычислительных затрат от сервера к веб-браузеру и могут привести к тому, что веб-сайты будут вести себя намного больше, чем нативные приложения (высокая скорость отклика и т. д.).

Веб-фреймворки упрощают веб-программирование на стороне сервера

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

Одна из наиболее важных операций, которые они выполняют, — предоставление простых механизмов для сопоставления URL-адресов различных ресурсов/страниц с определенными функциями обработчика. Это упрощает хранение кода, связанного с каждым типом ресурса, отдельно. Это также имеет преимущества с точки зрения обслуживания, поскольку вы можете изменить URL-адрес, используемый для доставки определенной функции, в одном месте, без необходимости изменять функцию обработчика.

Например, рассмотрим следующий код Django (Python), который сопоставляет два шаблона URL с двумя функциями представления. Первый шаблон гарантирует, что HTTP-запрос с URL-адресом ресурса /best будет передан функции с именем index() в модуле представлений. Вместо этого запрос с шаблоном " /best/junior " будет передан в функцию просмотра Junior().

Примечание. Первые параметры в функциях url() могут выглядеть немного странно (например, r'^junior/$' ), потому что они используют технику сопоставления с образцом, называемую "регулярными выражениями" (RegEx или RE). На данном этапе вам не нужно знать, как работают регулярные выражения, за исключением того, что они позволяют нам сопоставлять шаблоны в URL-адресе (а не жестко закодированные значения выше) и использовать их в качестве параметров в наших функциях представления. Например, в очень простом регулярном выражении может быть указано «соответствует одной прописной букве, за которой следует от 4 до 7 строчных букв».

Веб-фреймворк также позволяет функции представления легко извлекать информацию из базы данных. Структура наших данных определяется в моделях, которые представляют собой классы Python, определяющие поля, которые должны храниться в базовой базе данных. Если у нас есть модель с именем Team с полем "team_type", мы можем использовать простой синтаксис запроса, чтобы получить все команды определенного типа.

В приведенном ниже примере отображается список всех команд, которые имеют точное (с учетом регистра) значение team_type для "junior". Обратите внимание на формат: имя поля ( team_type ), за которым следует двойное подчеркивание, а затем используемый тип соответствия (в этот случай точный ). Есть много других типов спичек, и мы можем объединить их в гирляндную цепочку. Мы также можем контролировать порядок и количество возвращаемых результатов.

Очевидно, что веб-фреймворки могут помочь вам во многих других задачах. В следующей статье мы обсудим гораздо больше преимуществ и некоторые популярные веб-фреймворки.

Обзор

К этому моменту у вас должно быть хорошее представление об операциях, которые должен выполнять код на стороне сервера, и некоторые способы, с помощью которых серверная веб-инфраструктура может упростить эту задачу.

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

В этом руководстве рассматриваются основные функции компоновки Action Controller и Action View.

Прочитав это руководство, вы узнаете:

  • Как использовать различные методы рендеринга, встроенные в Rails.
  • Как создавать макеты с несколькими разделами контента.
  • Как использовать партиалы, чтобы высушить ваши представления.
  • Как использовать вложенные макеты (подшаблоны).

Главы

1 Обзор: как части сочетаются друг с другом

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

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

2 Создание ответов

2.1 Рендеринг по умолчанию: соглашение важнее конфигурации в действии

Вы слышали, что Rails продвигает "соглашение важнее конфигурации". Рендеринг по умолчанию является отличным примером этого. По умолчанию контроллеры в Rails автоматически отображают представления с именами, соответствующими допустимым маршрутам.Например, если у вас есть этот код в вашем классе BooksController:

И следующее в вашем файле маршрутов:

И у вас есть файл представления app/views/books/index.html.erb :

Rails автоматически отобразит app/views/books/index.html.erb, когда вы перейдете к /books и увидите "Книги скоро появятся!" на вашем экране.

Однако экран, который появится в ближайшее время, мало полезен, поэтому вскоре вы создадите свою модель Book и добавите действие index в BooksController :

Обратите внимание, что у нас нет явного рендеринга в конце действия индекса в соответствии с принципом "соглашение важнее конфигурации". Правило состоит в том, что если вы не визуализируете что-то явно в конце действия контроллера, Rails автоматически ищет шаблон action_name.html.erb в пути представления контроллера и визуализирует его. Так что в этом случае Rails отобразит файл app/views/books/index.html.erb.

Если мы хотим отобразить свойства всех книг в нашем представлении, мы можем сделать это с помощью шаблона ERB следующим образом:

Фактическая отрисовка выполняется вложенными классами модуля ActionView::Template::Handlers . В этом руководстве этот процесс не рассматривается, но важно знать, что расширение файла в вашем представлении определяет выбор обработчика шаблона.

2.2 Использование визуализации

Если вы хотите увидеть точные результаты вызова рендеринга без необходимости его проверки в браузере, вы можете вызвать render_to_string . Этот метод принимает те же параметры, что и render , но вместо отправки ответа в браузер возвращает строку.

2.2.1 Визуализация представления действия

Если вы хотите отобразить представление, соответствующее другому шаблону в том же контроллере, вы можете использовать render с именем представления:

Если вызов обновления завершится ошибкой, вызов действия обновления в этом контроллере отобразит шаблон edit.html.erb, принадлежащий тому же контроллеру.

Если вы предпочитаете, вы можете использовать символ вместо строки, чтобы указать отображаемое действие:

2.2.2 Визуализация шаблона действия из другого контроллера

Что делать, если вы хотите отобразить шаблон из совершенно другого контроллера, отличного от того, который содержит код действия? Вы также можете сделать это с помощью render , который принимает полный путь (относительно app/views ) шаблона для рендеринга. Например, если вы запускаете код в AdminProductsController, который находится в app/controllers/admin , вы можете отображать результаты действия в шаблоне в app/views/products следующим образом:

Rails знает, что это представление принадлежит другому контроллеру, благодаря встроенному символу косой черты в строке. Если вы хотите быть явным, вы можете использовать параметр :template (который требовался в Rails 2.2 и более ранних версиях):

2.2.3 Подведение итогов

Приведенные выше два способа рендеринга (рендеринг шаблона другого действия в том же контроллере и рендеринг шаблона другого действия в другом контроллере) на самом деле являются вариантами одной и той же операции.

Фактически, в классе BooksController внутри действия обновления, где мы хотим отображать шаблон редактирования, если книга не обновляется успешно, все следующие вызовы рендеринга будут отображать шаблон edit.html.erb в каталог представлений/книг:

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

2.2.4 Использование рендеринга с :inline

Метод рендеринга может полностью обойтись без представления, если вы хотите использовать параметр :inline для предоставления ERB как часть вызова метода. Это совершенно верно:

Есть веская причина для использования этой опции. Смешивание ERB с вашими контроллерами нарушает MVC-ориентацию Rails и затрудняет другим разработчикам следование логике вашего проекта. Вместо этого используйте отдельное представление erb.

По умолчанию встроенный рендеринг использует ERB. Вместо этого вы можете заставить его использовать Builder с помощью параметра :type:

2.2.5 Отображение текста

Вы можете отправить обычный текст — без всякой разметки — обратно в браузер, используя параметр :plain для рендеринга:

Визуализация чистого текста наиболее полезна, когда вы отвечаете на запросы Ajax или веб-службы, которые ожидают чего-то другого, кроме правильного HTML.

По умолчанию, если вы используете параметр :plain, текст отображается без использования текущего макета. Если вы хотите, чтобы Rails поместил текст в текущий макет, вам нужно добавить параметр layout: true и использовать расширение .text.erb для файла макета.

2.2.6 Визуализация HTML

Вы можете отправить строку HTML обратно в браузер, используя параметр :html для отображения:

Это удобно при отображении небольшого фрагмента HTML-кода. Однако вы можете подумать о переносе его в файл шаблона, если разметка сложная.

При использовании параметра html: объекты HTML будут экранированы, если строка не составлена ​​с помощью API-интерфейсов, поддерживающих html_safe.

2.2.7 Отрисовка JSON

JSON — это формат данных JavaScript, используемый многими библиотеками Ajax. Rails имеет встроенную поддержку преобразования объектов в JSON и рендеринга этого JSON обратно в браузер:

Вам не нужно вызывать to_json для объекта, который вы хотите отобразить. Если вы используете параметр :json, рендеринг автоматически вызовет to_json для вас.

2.2.8 Визуализация XML

Rails также имеет встроенную поддержку для преобразования объектов в XML и рендеринга этого XML обратно в вызывающую программу:

Вам не нужно вызывать to_xml для объекта, который вы хотите отобразить. Если вы используете параметр :xml, рендеринг автоматически вызовет to_xml для вас.

2.2.9 Рендеринг ванильного JavaScript

Rails может отображать ванильный JavaScript:

Это отправит предоставленную строку в браузер с типом MIME text/javascript .

2.2.10 Визуализация необработанного тела

Вы можете отправить необработанный контент обратно в браузер, не устанавливая какой-либо тип контента, используя параметр :body для рендеринга:

Этот параметр следует использовать только в том случае, если вам не важен тип содержания ответа. Использование :plain или :html может быть более подходящим в большинстве случаев.

Если это не переопределено, ваш ответ, возвращаемый этой опцией рендеринга, будет text/plain , так как это тип контента по умолчанию для ответа Action Dispatch.

2.2.11 Визуализация необработанного файла

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

Это рендерит необработанный файл (он не поддерживает ERB или другие обработчики). По умолчанию он отображается в текущем макете.

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

send_file часто является более быстрым и лучшим вариантом, если макет не требуется.

2.2.12 Визуализация объектов

Rails может отображать объекты в ответ на :render_in .

Это вызывает render_in для предоставленного объекта с текущим контекстом представления.

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

Вызовы метода рендеринга обычно принимают шесть параметров:

  • :content_type
  • :макет
  • :место
  • :статус
  • :форматы
  • :варианты
2.2.13.1 Параметр :content_type

По умолчанию Rails будет обслуживать результаты операции рендеринга с типом содержимого MIME text/html (или application/json, если вы используете параметр :json, или application/xml для параметра :xml). Иногда вам может понадобиться изменить это, и вы можете сделать это, установив параметр :content_type:

2.2.13.2 Параметр :layout

С большинством параметров рендеринга отображаемый контент отображается как часть текущего макета. Подробнее о макетах и ​​их использовании вы узнаете позже в этом руководстве.

Вы можете использовать параметр :layout, чтобы указать Rails использовать определенный файл в качестве макета для текущего действия:

Вы также можете указать Rails рендерить вообще без макета:

2.2.13.3 Параметр :location
2.2.13.4 Параметр :status

Rails понимает как числовые коды состояния, так и соответствующие символы, показанные ниже.

Если вы попытаетесь отобразить контент вместе с кодом состояния, не относящимся к контенту (100–199, 204, 205 или 304), он будет исключен из ответа.

2.2.13.5 Параметр :formats

Rails использует формат, указанный в запросе (или :html по умолчанию). Вы можете изменить это, передав параметру :formats символ или массив:

Если шаблон с указанным форматом не существует, возникает ошибка ActionView::MissingTemplate.

2.2.13.6 Параметр :variants

Это указывает Rails искать варианты шаблонов того же формата. Вы можете указать список вариантов, передав параметр :variants с символом или массивом.

Вот пример использования.

С этим набором вариантов Rails будет искать следующий набор шаблонов и использовать первый существующий.

  • app/views/home/index.html+mobile.erb
  • app/views/home/index.html+desktop.erb
  • app/views/home/index.html.erb

Если шаблон с указанным форматом не существует, возникает ошибка ActionView::MissingTemplate.

Вместо того, чтобы устанавливать вариант для вызова рендеринга, вы также можете установить его для объекта запроса в действии вашего контроллера.

2.2.14 Поиск макетов

Чтобы найти текущий макет, Rails сначала ищет файл в app/views/layouts с тем же базовым именем, что и у контроллера. Например, действия рендеринга из класса PhotosController будут использовать app/views/layouts/photos.html.erb (или app/views/layouts/photos.builder ). Если такого макета для конкретного контроллера нет, Rails будет использовать app/views/layouts/application.html.erb или app/views/layouts/application.builder . Если макета .erb нет, Rails будет использовать макет .builder, если он существует.Rails также предоставляет несколько способов более точного назначения определенных макетов отдельным контроллерам и действиям.

2.2.14.1 Указание макетов для контроллеров

Вы можете переопределить соглашения о макете по умолчанию в своих контроллерах, используя объявление макета. Например:

С этим объявлением все представления, отображаемые с помощью ProductsController, будут использовать app/views/layouts/inventory.html.erb в качестве своего макета.

Чтобы назначить определенный макет для всего приложения, используйте объявление макета в своем классе ApplicationController:

С этим объявлением все представления во всем приложении будут использовать app/views/layouts/main.html.erb для своего макета.

2.2.14.2 Выбор макетов во время выполнения

Вы можете использовать символ, чтобы отложить выбор макета до тех пор, пока запрос не будет обработан:

Теперь, если текущий пользователь является особым пользователем, он получит особый макет при просмотре продукта.

Вы даже можете использовать встроенный метод, например Proc, для определения макета. Например, если вы передаете объект Proc, блоку, который вы передаете Proc, будет предоставлен экземпляр контроллера, поэтому макет может быть определен на основе текущего запроса:

2.2.14.3 Условные макеты

Макеты, заданные на уровне контроллера, поддерживают параметры :only и :except. Эти параметры принимают либо имя метода, либо массив имен методов, соответствующих именам методов в контроллере:

С этим объявлением макет продукта будет использоваться для всего, кроме методов rss и index.

2.2.14.4 Наследование макета

Объявления макета располагаются каскадом вниз по иерархии, а более конкретные объявления макета всегда имеют приоритет над более общими. Например:

Расширения разметки XAML представляют собой важную функцию XAML, позволяющую задавать свойства для объектов или значений, на которые косвенно ссылаются другие источники. Расширения разметки XAML особенно важны для совместного использования объектов и ссылок на константы, используемые во всем приложении, но наибольшую пользу они находят в привязках данных.

Расширения разметки XAML

Как правило, вы используете XAML для установки свойств объекта в явные значения, такие как строка, число, член перечисления или строка, которая преобразуется в значение за кулисами.

Однако иногда свойства должны ссылаться на значения, определенные где-то еще, или которые могут потребовать небольшой обработки кодом во время выполнения. Для этих целей доступны расширения разметки XAML.

Эти расширения разметки XAML не являются расширениями XML. XAML — это полностью легальный XML. Их называют «расширениями», потому что они поддерживаются кодом в классах, реализующих IMarkupExtension. Вы можете написать свои собственные расширения разметки.

Во многих случаях расширения разметки XAML сразу распознаются в файлах XAML, поскольку они отображаются как настройки атрибутов, разделенные фигурными скобками: < и >, но иногда расширения разметки отображаются в разметке как обычные элементы.

Общие ресурсы

Некоторые страницы XAML содержат несколько представлений с одинаковыми значениями свойств. Например, многие настройки свойств для этих объектов Button одинаковы:

Если нужно изменить одно из этих свойств, лучше всего сделать это один раз, а не три раза. Если бы это был код, вы, вероятно, использовали бы константы и статические объекты только для чтения, чтобы обеспечить согласованность таких значений и легкость их изменения.

В XAML одним из популярных решений является хранение таких значений или объектов в словаре ресурсов. Класс VisualElement определяет свойство с именем Resources типа ResourceDictionary, которое представляет собой словарь с ключами типа string и значениями типа object. Вы можете помещать объекты в этот словарь, а затем ссылаться на них из разметки, и все это в XAML.

Чтобы использовать словарь ресурсов на странице, добавьте пару тегов элементов свойств Resources. Удобнее всего разместить их вверху страницы:

Также необходимо явно включать теги ResourceDictionary:

Теперь в словарь ресурсов можно добавлять объекты и значения различных типов. Эти типы должны быть инстанцируемыми. Например, они не могут быть абстрактными классами. Эти типы также должны иметь общедоступный конструктор без параметров. Для каждого элемента требуется ключ словаря, указанный в атрибуте x:Key. Например:

Эти два элемента являются значениями структурного типа LayoutOptions , и каждый из них имеет уникальный ключ и набор одного или двух свойств. В коде и разметке гораздо чаще используются статические поля LayoutOptions, но здесь удобнее задавать свойства.

Теперь необходимо установить свойства HorizontalOptions и VerticalOptions этих кнопок для этих ресурсов, и это делается с помощью расширения разметки StaticResource XAML:

Расширение разметки StaticResource всегда ограничивается фигурными скобками и включает ключ словаря.

Имя StaticResource отличает его от DynamicResource , который также поддерживает Xamarin.Forms. DynamicResource предназначен для ключей словаря, связанных со значениями, которые могут измениться во время выполнения, а StaticResource обращается к элементам из словаря только один раз при создании элементов на странице.

Для свойства BorderWidth необходимо сохранить в словаре двойное значение. XAML удобно определяет теги для распространенных типов данных, таких как x:Double и x:Int32 :

Вам не нужно помещать его в три строки. Эта словарная запись для этого угла поворота занимает всего одну строку:

На эти два ресурса можно ссылаться так же, как и на значения LayoutOptions:

Для ресурсов типа Color можно использовать те же строковые представления, что и при непосредственном назначении атрибутов этих типов. Преобразователи типов вызываются при создании ресурса. Вот ресурс типа Color :

Часто программы устанавливают для свойства FontSize элемент перечисления NamedSize, например Large . Класс FontSizeConverter работает за кулисами, чтобы преобразовать его в значение, зависящее от платформы, с помощью метода Device.GetNamedSized. Однако при определении ресурса размера шрифта имеет смысл использовать числовое значение, показанное здесь как тип x:Double:

Теперь все свойства, кроме Text, определяются настройками ресурса:

Также можно использовать OnPlatform в словаре ресурсов для определения различных значений для платформ. Вот как объект OnPlatform может быть частью словаря ресурсов для разных цветов текста:

Обратите внимание, что OnPlatform получает как атрибут x:Key, поскольку это объект в словаре, так и атрибут x:TypeArguments, поскольку это универсальный класс. Атрибуты iOS , Android и UWP преобразуются в значения Color при инициализации объекта.

Вот окончательный полный файл XAML с тремя кнопками для доступа к шести общим значениям:

Скриншоты подтверждают согласованность стиля и стиль, зависящий от платформы:

Хотя чаще всего коллекция Resources определяется в верхней части страницы, имейте в виду, что свойство Resources определяется VisualElement , и вы можете иметь коллекции Resources в других элементах на странице. Например, попробуйте добавить его в StackLayout в этом примере:

Вы обнаружите, что цвет текста кнопок теперь синий. По сути, всякий раз, когда синтаксический анализатор XAML встречает расширение разметки StaticResource, он выполняет поиск по визуальному дереву и использует первый найденный ResourceDictionary, содержащий этот ключ.

Одним из наиболее распространенных типов объектов, хранящихся в словарях ресурсов, является стиль Xamarin.Forms Style , определяющий набор параметров свойств. Стили обсуждаются в статье Стили.

Иногда разработчики, плохо знакомые с XAML, задаются вопросом, могут ли они поместить визуальный элемент, такой как метка или кнопка, в ResourceDictionary . Хотя это, безусловно, возможно, в этом нет особого смысла. Целью ResourceDictionary является совместное использование объектов. Визуальный элемент не может быть общим. Один и тот же экземпляр не может появляться дважды на одной странице.

Расширение x:Static Markup

Несмотря на сходство названий, x:Static и StaticResource очень разные. StaticResource возвращает объект из словаря ресурсов, в то время как x:Static обращается к одному из следующих:

  • общедоступное статическое поле
  • общедоступное статическое свойство
  • общедоступное постоянное поле
  • член перечисления.

Расширение разметки StaticResource поддерживается реализациями XAML, которые определяют словарь ресурсов, а x:Static является неотъемлемой частью XAML, о чем свидетельствует префикс x.

Вот несколько примеров, демонстрирующих, как x:Static может явно ссылаться на статические поля и члены перечисления:

Пока это не очень впечатляет. Но расширение разметки x:Static также может ссылаться на статические поля или свойства из вашего собственного кода. Например, вот класс AppConstants, который содержит некоторые статические поля, которые вы можете использовать на нескольких страницах в приложении:

Чтобы сослаться на статические поля этого класса в файле XAML, вам потребуется указать в файле XAML, где находится этот файл. Вы делаете это с помощью объявления пространства имен XML.

Напоминаем, что файлы XAML, созданные как часть стандартного шаблона Xamarin.Forms XAML, содержат два объявления пространства имен XML: одно для доступа к классам Xamarin.Forms, а другое для ссылки на теги и атрибуты, встроенные в XAML:

Оба этих объявления пространств имен включены в пример StaticConstantsPage. Обратите внимание, что для размеров BoxView заданы значения Math.PI и Math.E , но они масштабируются с коэффициентом 100:

Размер результирующего BoxView относительно экрана зависит от платформы:

Другие стандартные расширения разметки

Несколько расширений разметки встроены в XAML и поддерживаются в XAML-файлах Xamarin.Forms. Некоторые из них не используются очень часто, но необходимы, когда они вам нужны:

  • Если свойство по умолчанию имеет ненулевое значение, но вы хотите установить для него значение null , задайте для него расширение разметки.
  • Если свойство имеет тип Type , вы можете назначить его объекту Type с помощью расширения разметки .
  • Вы можете определять массивы в XAML с помощью расширения разметки x:Array. Это расширение разметки имеет обязательный атрибут Type, который указывает тип элементов в массиве.
  • Расширение разметки Binding обсуждается в части 4. Основы привязки данных.
  • Расширение разметки RelativeSource обсуждается в разделе Relative Bindings.

Расширение разметки ConstraintExpression

Расширения разметки могут иметь свойства, но они не задаются как атрибуты XML. В расширении разметки параметры свойств разделяются запятыми, а внутри фигурных скобок кавычки не отображаются.

Это можно проиллюстрировать с помощью расширения разметки Xamarin.Forms с именем ConstraintExpression , которое используется с классом RelativeLayout. Вы можете указать местоположение или размер дочернего представления как константу или относительно родительского или другого именованного представления. Синтаксис ConstraintExpression позволяет вам установить положение или размер представления, используя фактор, умноженный на свойство другого представления, плюс константу. Для всего более сложного требуется код.

Вот пример:

Возможно, самый важный урок, который вы должны извлечь из этого примера, касается синтаксиса расширения разметки: внутри фигурных скобок расширения разметки не должно быть кавычек. При вводе расширения разметки в XAML-файле естественно захотеть заключить значения свойств в кавычки. Не поддавайтесь искушению!

Вот работающая программа:

Обзор

Расширения разметки XAML, показанные здесь, обеспечивают важную поддержку файлов XAML. Но, возможно, наиболее ценным расширением разметки XAML является Binding , которое рассматривается в следующей части этой серии, часть 4. Основы привязки данных.

В этом руководстве рассматриваются основные функции компоновки Action Controller и Action View.

Прочитав это руководство, вы узнаете:

  • Как использовать различные методы рендеринга, встроенные в Rails.
  • Как создавать макеты с несколькими разделами контента.
  • Как использовать партиалы, чтобы высушить ваши представления.
  • Как использовать вложенные макеты (подшаблоны).

Главы

1 Обзор: как части сочетаются друг с другом

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

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

2 Создание ответов

2.1 Рендеринг по умолчанию: соглашение важнее конфигурации в действии

Вы слышали, что Rails продвигает "соглашение важнее конфигурации". Рендеринг по умолчанию является отличным примером этого. По умолчанию контроллеры в Rails автоматически отображают представления с именами, соответствующими допустимым маршрутам. Например, если у вас есть этот код в вашем классе BooksController:

И следующее в вашем файле маршрутов:

И у вас есть файл представления app/views/books/index.html.erb :

Rails автоматически отобразит app/views/books/index.html.erb, когда вы перейдете к /books и увидите "Книги скоро появятся!" на вашем экране.

Однако экран, который появится в ближайшее время, мало полезен, поэтому вскоре вы создадите свою модель Book и добавите действие index в BooksController :

Обратите внимание, что у нас нет явного рендеринга в конце действия индекса в соответствии с принципом "соглашение важнее конфигурации".Правило состоит в том, что если вы не визуализируете что-то явно в конце действия контроллера, Rails автоматически ищет шаблон action_name.html.erb в пути представления контроллера и визуализирует его. Так что в этом случае Rails отобразит файл app/views/books/index.html.erb.

Если мы хотим отобразить свойства всех книг в нашем представлении, мы можем сделать это с помощью шаблона ERB следующим образом:

Фактическая отрисовка выполняется вложенными классами модуля ActionView::Template::Handlers . В этом руководстве этот процесс не рассматривается, но важно знать, что расширение файла в вашем представлении определяет выбор обработчика шаблона.

2.2 Использование визуализации

Если вы хотите увидеть точные результаты вызова рендеринга без необходимости его проверки в браузере, вы можете вызвать render_to_string . Этот метод принимает те же параметры, что и render , но вместо отправки ответа в браузер возвращает строку.

2.2.1 Визуализация представления действия

Если вы хотите отобразить представление, соответствующее другому шаблону в том же контроллере, вы можете использовать render с именем представления:

Если вызов обновления завершится ошибкой, вызов действия обновления в этом контроллере отобразит шаблон edit.html.erb, принадлежащий тому же контроллеру.

Если вы предпочитаете, вы можете использовать символ вместо строки, чтобы указать отображаемое действие:

2.2.2 Визуализация шаблона действия из другого контроллера

Что делать, если вы хотите отобразить шаблон из совершенно другого контроллера, отличного от того, который содержит код действия? Вы также можете сделать это с помощью render , который принимает полный путь (относительно app/views ) шаблона для рендеринга. Например, если вы запускаете код в AdminProductsController, который находится в app/controllers/admin , вы можете отображать результаты действия в шаблоне в app/views/products следующим образом:

Rails знает, что это представление принадлежит другому контроллеру, благодаря встроенному символу косой черты в строке. Если вы хотите быть явным, вы можете использовать параметр :template (который требовался в Rails 2.2 и более ранних версиях):

2.2.3 Подведение итогов

Приведенные выше два способа рендеринга (рендеринг шаблона другого действия в том же контроллере и рендеринг шаблона другого действия в другом контроллере) на самом деле являются вариантами одной и той же операции.

Фактически, в классе BooksController внутри действия обновления, где мы хотим отображать шаблон редактирования, если книга не обновляется успешно, все следующие вызовы рендеринга будут отображать шаблон edit.html.erb в каталог представлений/книг:

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

2.2.4 Использование рендеринга с :inline

Метод рендеринга может полностью обойтись без представления, если вы хотите использовать параметр :inline для предоставления ERB как часть вызова метода. Это совершенно верно:

Есть веская причина для использования этой опции. Смешивание ERB с вашими контроллерами нарушает MVC-ориентацию Rails и затрудняет другим разработчикам следование логике вашего проекта. Вместо этого используйте отдельное представление erb.

По умолчанию встроенный рендеринг использует ERB. Вместо этого вы можете заставить его использовать Builder с помощью параметра :type:

2.2.5 Отображение текста

Вы можете отправить обычный текст — без всякой разметки — обратно в браузер, используя параметр :plain для рендеринга:

Визуализация чистого текста наиболее полезна, когда вы отвечаете на запросы Ajax или веб-службы, которые ожидают чего-то другого, кроме правильного HTML.

По умолчанию, если вы используете параметр :plain, текст отображается без использования текущего макета. Если вы хотите, чтобы Rails поместил текст в текущий макет, вам нужно добавить параметр layout: true и использовать расширение .text.erb для файла макета.

2.2.6 Визуализация HTML

Вы можете отправить строку HTML обратно в браузер, используя параметр :html для отображения:

Это удобно при отображении небольшого фрагмента HTML-кода. Однако вы можете подумать о переносе его в файл шаблона, если разметка сложная.

При использовании параметра html: объекты HTML будут экранированы, если строка не составлена ​​с помощью API-интерфейсов, поддерживающих html_safe.

2.2.7 Визуализация JSON

JSON — это формат данных JavaScript, используемый многими библиотеками Ajax. Rails имеет встроенную поддержку преобразования объектов в JSON и рендеринга этого JSON обратно в браузер:

Вам не нужно вызывать to_json для объекта, который вы хотите отобразить. Если вы используете параметр :json, рендеринг автоматически вызовет to_json для вас.

2.2.8 Визуализация XML

Rails также имеет встроенную поддержку для преобразования объектов в XML и рендеринга этого XML обратно в вызывающую программу:

Вам не нужно вызывать to_xml для объекта, который вы хотите отобразить.Если вы используете параметр :xml, рендеринг автоматически вызовет to_xml для вас.

2.2.9 Рендеринг ванильного JavaScript

Rails может отображать ванильный JavaScript:

Это отправит предоставленную строку в браузер с типом MIME text/javascript .

2.2.10 Визуализация необработанного тела

Вы можете отправить необработанный контент обратно в браузер, не устанавливая какой-либо тип контента, используя параметр :body для рендеринга:

Этот параметр следует использовать только в том случае, если вам не важен тип содержания ответа. Использование :plain или :html может быть более подходящим в большинстве случаев.

Если это не переопределено, ваш ответ, возвращаемый этой опцией рендеринга, будет text/plain , так как это тип контента по умолчанию для ответа Action Dispatch.

2.2.11 Визуализация необработанного файла

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

Это рендерит необработанный файл (он не поддерживает ERB или другие обработчики). По умолчанию он отображается в текущем макете.

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

send_file часто является более быстрым и лучшим вариантом, если макет не требуется.

2.2.12 Визуализация объектов

Rails может отображать объекты в ответ на :render_in .

Это вызывает render_in для предоставленного объекта с текущим контекстом представления.

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

Вызовы метода рендеринга обычно принимают шесть параметров:

  • :content_type
  • :макет
  • :место
  • :статус
  • :форматы
  • :варианты
2.2.13.1 Параметр :content_type

По умолчанию Rails будет обслуживать результаты операции рендеринга с типом содержимого MIME text/html (или application/json, если вы используете параметр :json, или application/xml для параметра :xml). Иногда вам может понадобиться изменить это, и вы можете сделать это, установив параметр :content_type:

2.2.13.2 Параметр :layout

С большинством параметров рендеринга отображаемый контент отображается как часть текущего макета. Подробнее о макетах и ​​их использовании вы узнаете позже в этом руководстве.

Вы можете использовать параметр :layout, чтобы указать Rails использовать определенный файл в качестве макета для текущего действия:

Вы также можете указать Rails рендерить вообще без макета:

2.2.13.3 Параметр :location
2.2.13.4 Параметр :status

Rails понимает как числовые коды состояния, так и соответствующие символы, показанные ниже.

Если вы попытаетесь отобразить контент вместе с кодом состояния, не относящимся к контенту (100–199, 204, 205 или 304), он будет исключен из ответа.

2.2.13.5 Параметр :formats

Rails использует формат, указанный в запросе (или :html по умолчанию). Вы можете изменить это, передав параметру :formats символ или массив:

Если шаблон с указанным форматом не существует, возникает ошибка ActionView::MissingTemplate.

2.2.13.6 Параметр :variants

Это указывает Rails искать варианты шаблонов того же формата. Вы можете указать список вариантов, передав параметр :variants с символом или массивом.

Вот пример использования.

С этим набором вариантов Rails будет искать следующий набор шаблонов и использовать первый существующий.

  • app/views/home/index.html+mobile.erb
  • app/views/home/index.html+desktop.erb
  • app/views/home/index.html.erb

Если шаблон с указанным форматом не существует, возникает ошибка ActionView::MissingTemplate.

Вместо того, чтобы устанавливать вариант для вызова рендеринга, вы также можете установить его для объекта запроса в действии вашего контроллера.

2.2.14 Поиск макетов

Чтобы найти текущий макет, Rails сначала ищет файл в app/views/layouts с тем же базовым именем, что и у контроллера. Например, действия рендеринга из класса PhotosController будут использовать app/views/layouts/photos.html.erb (или app/views/layouts/photos.builder ). Если такого макета для конкретного контроллера нет, Rails будет использовать app/views/layouts/application.html.erb или app/views/layouts/application.builder . Если макета .erb нет, Rails будет использовать макет .builder, если он существует. Rails также предоставляет несколько способов более точного назначения определенных макетов отдельным контроллерам и действиям.

2.2.14.1 Указание макетов для контроллеров

Вы можете переопределить соглашения о макете по умолчанию в своих контроллерах, используя объявление макета. Например:

С этим объявлением все представления, отображаемые с помощью ProductsController, будут использовать app/views/layouts/inventory.html.erb в качестве своего макета.

Чтобы назначить определенный макет для всего приложения, используйте объявление макета в своем классе ApplicationController:

С этим объявлением все представления во всем приложении будут использовать app/views/layouts/main.html.erb для своего макета.

2.2.14.2 Выбор макетов во время выполнения

Вы можете использовать символ, чтобы отложить выбор макета до тех пор, пока запрос не будет обработан:

Теперь, если текущий пользователь является особым пользователем, он получит особый макет при просмотре продукта.

Вы даже можете использовать встроенный метод, например Proc, для определения макета. Например, если вы передаете объект Proc, блоку, который вы передаете Proc, будет предоставлен экземпляр контроллера, поэтому макет может быть определен на основе текущего запроса:

2.2.14.3 Условные макеты

Макеты, заданные на уровне контроллера, поддерживают параметры :only и :except. Эти параметры принимают либо имя метода, либо массив имен методов, соответствующих именам методов в контроллере:

С этим объявлением макет продукта будет использоваться для всего, кроме методов rss и index.

2.2.14.4 Наследование макета

Объявления макета располагаются каскадом вниз по иерархии, а более конкретные объявления макета всегда имеют приоритет над более общими. Например:

Читайте также: