Мультиблог на Ruby on Rails. Работа с шаблоном. Подключение CSS и JS. Урок 5.

При написании данного урока мною было принято решение не верстать с нуля, а взять за основу готовый бесплатный шаблон «Clean blog». Сделано так потому, что у нас урок всё-таки больше по созданию блога, а не по вёрстке. Тем более, на сайте уже есть уроки по HTML, где я постарался раскрыть данную тему максимально доходчиво. 

Создание базового шаблона

Грубо говоря, под базовым шаблоном понимаются те части HTML каркаса страницы, которые не меняются - у большинства сайтов это шапка, подвал, левое меню и прочие элементы навигации. Базовый шаблон в Ruby on Rails находится по пути app/views/layouts/application.html.erb; удалим всё, что в нём есть и разместим там содержимое файла index.html из нашего готового шаблона. Теперь если обновить главную страничку, то можно увидеть что она поменялась, но выглядит как-то не круто - это всё потому, что у нас не подключены стили CSS.

Подключение стилей

В "рельсах" за стили отвечает файл app/assets/stylesheets/application.css В нём, помимо комментариев, есть две конструкции: 

  1. *= require_tree . - рекурсивно подключает все CSS файлы, которые находятся в папке app/assets/stylesheets/
  2. *= require_self - отвечает за стили, которые находятся уже в самом файле application.css

Но чтобы это всё работало, надо подключить CSS файл в базовый шаблон:

<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>

Смотрим какие CSS файлы у нас есть в шаблоне. Возьмём к примеру файл vendor/bootstrap/css/bootstrap.min.css Как я его подключил? Я создал внутри папки app/assets/stylesheets/ папку bootstrap и в неё скопировал файл bootstrap.min.css из самого шаблона. Теперь если обновить страничку, то можно увидеть что стили подключены. Аналогичные действия я проделал и для других CSS файлов: 

vendor/fontawesome-free/css/all.min.css
css/clean-blog.min.css

Однако, если мы сейчас обновим страничку, то обнаружим что не все иконки подгрузились. Связано это с тем, что в css файле путь к шрифту смотрит на папку webfonts, которая лежит на уровень выше - в нашем случае это папка public. Значит всё, что нужно сделать, это скопировать папку /vendor/fontawesome-free/webfonts в папку /public нашего проекта. И если сейчас обновить страничку, то мы увидим что все шрифты подгрузились.

Подключение Javascript файлов

Первым делом, выносим все JS файлы в папку app/javascript В нашем случае это файлы jquery.min.js, bootstrap.bundle.min.js и clean-blog.min.js Соответственно ссылки на эти файлы из самого шаблона мы удаляем, а вместо этого размещаем их следующим образом:

<%= javascript_include_tag 'jquery.min.js' %>
<%= javascript_include_tag 'bootstrap.bundle.min.js' %>
<%= javascript_include_tag 'clean-blog.min.js' %>

Обновление страниц без перезагрузки. Turbolinks. 

У Ruby on Rails есть такая удобная фишка, как обновление контентной части без перезагрузки самой страницы. Чтобы это заработало, необходимо в базовый шаблон разместить тэг:

<%= javascript_importmap_tags %>

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

Понятие дочерней страницы

Дочерняя страница - это view шаблон, который путём наследования подключает базовый (родительский) шаблон и изменяет данные в специально отведённых для этого секциях. Если попытаться перевести всё это на более понятный язык, то давайте ответим себе на вопрос: "что у нас обычно меняется при переходе по страничкам сайта?". Правильно, это контентная часть. Но чтобы она менялась, надо как-то обозначить секцию для контента в базовом шаблоне. За это отвечает следующая конструкция:

<%= yield %>

Если же говорить о дочерней странице, то таковой у нас является страничка index.html.erb Опять же, почему именно она? Потому что мы находимся на главной странице, которая привязана к action index контролера posts; а сам контролер, в соответствии со своим расположением, обращается к файлу views/posts/index.html.erb Теперь вопрос в том, а где эту конструкцию yield разместить? Конечно же в контентной части, ровно там, где у нас выводятся посты на главной странице. 

Размещение нескольких секций yield

Всё это время мы говорили о секции для контента, однако у нас таких секций может быть несколько. Одна для изменения заголовка H1, вторая для изменения тэга title, третья для размещения картинки. Тут возникает вопрос, как обозначить их все в базовом шаблоне? Разберём на примере заголовка H1, секцию для которого обозначим так:

<h1><%= yield(:h1) %></h1>

А в дочернем шаблоне переопределим это место в index.html.erb следующим образом:

<% content_for :h1 do %>
Список записей
<% end %>

Аналогичное действие проделываем и для тэга title:

<title><%= yield(:title) %></title>

В дочернем шаблоне соответственно секцию подгружаем так:

<% content_for :title do %>
Список записей
<% end %>

Стилизация отдельного поста внутри цикла или понятие частичного (partial) шаблона

Теперь у нас главная страничка выглядит более красиво, однако этого нельзя сказать об отображении самих постов - там по-прежнему неструктурированная каша. Именно для этих целей RoR предоставляет рендеринг шаблонов внутри шаблонов (иногда их называют ещё partial шаблоны, так как они не предполагают наследования). Используется это в основном там, где необходимо оформить элементы, вывод которых происходит в цикле. Я разместил такой файл по пути app/views/posts/_post.html.erb (partial шаблон принято именовать с символа _) со следующим содержимым:

<div class="post-preview">
  <a href="#">
    <h2 class="post-title">
      <%= post.title %>
    </h2>
    <h3 class="post-subtitle">
      <%= post.body.truncate(255, '…') %>
    </h3>
  </a>
  <p class="post-meta">Posted by
    <a href="#">Start Bootstrap</a>
    on <%= post.created_at.strftime('%d-%m-%Y %H:%M') %>
  </p>
</div>
<hr>

Тут наверное стоит рассказать о вспомогательных методах:

truncate - отвечает за обрезку контента до определённого количества символов. Первый аргумент - это количество таких символов, второй - строка, которая будет идти в конце текста (в данном случае троеточие). 
strftime - форматирование даты. Хочу обратить внимание, что поле created_at у нас всегда создаётся по умолчанию при создании миграции и заполняется автоматом. 

А в самом шаблоне index.html.erb мы будем подгружать этот partial шаблон так:

<% @posts.each do |post| %>
  <%= render 'post', post: post %>
<% end %>

То есть здесь мы в цикле итерируем переменную posts, и на каждом шаге передаём статью (локальная переменная post) в шаблон _post.html.erb

Добавление статичных картинок

На главной странице у нас должна отображаться картинка about-bg.jpg, которую я разместил в папке /public/images/ Но прежде чем её вывести, сперва необходимо обозначить соответствующую секцию в базовом шаблоне:

<%= yield(:image) %>

Теперь перезаписываем секцию родительского шаблона:

<% content_for :image do %><%= '/images/about-bg.jpg' %><% end %>

Обновляем страничку и убеждаемся что картинка на месте. 

Итог работы

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

Урок получился достаточно объёмным, поэтому чтобы вы ничего не упустили, вот коммит со всеми текущими изменениями в помощь.