Представления

Введение

Представления (views, или, как их еще называют - вьюхи) - это простейшая часть структуры MVC - можно сказать, что это набор HTML шаблонов, которые получают переменные из контроллера и которые отсылаются браузеру. Это и есть ваша веб-страница. Обычно представление содержит сниппеты для обработки полученных переменных, такие как например циклы для отображения каждого поста в блоге. Часто их называют шаблонами представлений.

Типичное представление можно найти по следующему пути - app/views/controller_name/action_name.html.erb, где controller_name - имя контроллера, с которым связано представление, а action_name.html.erb это соответствующий метод в контроллере, выполняющийся непосредственно перед рендерингом представления.

В итоге, контроллер PostsController после выполнения действия #index, незамедлительно отрендерит app/views/posts/index.html.erb. Конечно, вы можете напрямую сказать контроллеру, какой именно файл необходимо отрендерить, но зачем? С таким подходом к структуре каталогов и их наименованиям, вам (и Rails) всегда будет проще найти нужное представление.

Для использования полученной из контроллера переменной, используйте те же имена, что вы использовали и в контроллере: @user.first_name или @posts или @some_other_variable.

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

Пункты для размышления

Постарайтесь ответить на предложенные вопросы. После выполнения задания попробуйте ответить на них ещё раз

  • Что такое макет?
  • В чем разница между шаблоном представления и макетом?
  • Что такое препроцессоры?
  • Зачем они нужны?
  • Как заставить препроцессор обработать файл?
  • Какой получается тип файла после обработки препроцессором файлов *.html.erb, *.css.scss?
  • Какова разница между тэгами <%= и <%?
  • Что такое парциал?
  • Как вставить его в представление?
  • Как отличить представление от парциала?
  • Как передать локальную переменную в парциал?
  • Какой прием использует Rails для рендеринга одного пользователя? Всех пользователей?
  • Что такое ресурсные теги и зачем они нужны?

Макеты/Layouts

Первое, что стОит отметить, так это то, что шаблон, который рендерится из контроллера, на самом деле не является полной веб-страницей. Он не содержит тэги <head> или объявления DOCTYPE, или какую-то другую структуру, общую для всех веб-страниц. Именно потому, что все это присутствует на всех ваших страницах, создатели Rails включили этот код в собственный файл, который называется "макет". Макеты находятся в папке app/views/layouts.

Для совершенно нового приложения, макет application.html.erb предельно прост. Он содержит основные тэги (например <html> и <body>), а также пару сниппетов для загрузки Javascript и CSS, используемых на вашей странице. Вы будете добавлять в макет дополнительный код для использования на всех ваших страницах. Обычно это навигационные меню, футеры и сниппеты для отображения сообщений flash.

Если макет это оболочка вокруг отдельной страницы, то как же эта страница в него вставляется? Здесь надо возвратиться к магии метода #yield, которую вы видели в уроке, посвященном блокам. Шаблон представления app/views/posts/index.html.erb просто вставляется вместо этого метода. По мере накопления опыта, вы научитесь им манипулировать, но пока будем считать что все так просто.

Препроцессоры

Несомненно вы заметили странный HTML код между тэгами <%= и %>. Это Embedded Ruby (ERB). Эти тэги используются для выполнения кода Ruby внутри вашего HTML. HTML статичен, поэтому вам нужно некоторое количество Ruby для придания динамичности, такой как циклы, условия или работа с переменными. ERB (и другие подобные языки, например HAML) делает именно это.

Внутри этих тегов код выполняется как обыкновенный код Ruby. Например <%= "<em>Это курсивный текст</em>" %> выдаст курсивную строчку как и <em>Это курсивный текст</em>, а из <%= @user.first_name %> мы получим joe.

Различие между <% и <%= в том, что <%= отобразит все что вернется из ERB тэгов. <% напротив, после выполнения кода не отобразит ни строчки, независимо от того, что вернул код.

Большинство используемых вами тэгов будет <%=, в основном для подстановки важных составляющих переменных экземпляра, полученных из контроллера, как в <%= @user.first_name %> из примера выше. Использовать <% вы будете для исключительно относящихся к коду условий if и циклов each, которые конечно нет смысла выводить на экран (все, что должно выводиться, будет находиться внутри цикла).

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

    <% if current_user.signed_in? %>
      <ul>
        <% @users.each do |user| %>
          <li><%= user.first_name %></li>
        <% end %>
      </ul>
    <% else %>
      <strong>Залогиньтесь!</strong>
    <% end %>

Помните, что необходимо завершать условия и циклы с помощью <% end %>! (Вы наверняка несколько раз про это забудете).

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

    <ul>
      <li>Bob</li>
      <li>Joe</li>
      <li>Nancy</li>
    </ul>

Код будет значительно короче, если пользователь не вошел в систему:

    <strong>Залогиньтесь!</strong>

В приведенном выше коде, если бы мы случайно использовали <%= в строчке с циклом, например <%= @users.each do |user| %>, то код отработал бы нормально, но из-за того, что each возвращает набор данных, мы также увидели бы дамп переменной @users на странице (и это не очень профессионально). На первых порах это будет с вами часто случаться, но вы быстро исправитесь.

Как работают препроцессоры?

Важно заметить, что вышеприведенный код исполнится на сервере раньше, чем окончательный HTML будет отправлен браузеру (об Asset Pipeline мы поговорим в следующем уроке). Это происходит потому, что когда идет рендеринг шаблона в Rails, он сначала запускает "препроцессор", такой как ERB. Rails знает что необходимо осуществить такой процессинг файла, так как он имеет расширение .html.erb.

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

Существуют также другие препроцессоры, которыми вы также будете пользоваться. Файлы с расширением .css.scss использует препроцессор SASS, и они становятся обычными файлами CSS. Файлы .js.coffee, после обработки препроцессором Coffeescript, становятся обычным Javascript. В обоих случаях, языки препроцессинга облегчают вам жизнь, предоставляя вам дополнительные инструменты для использования (как наличие циклов и работу с переменными), и преобразуя файлы в ванильный CSS, или Javascript, или HTML.

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

Парциалы/Partials

Другой приятной возможностью в Rails является разбиение ваших представлений на парциалы. Это помогает во многом - делает код более кратким и легким для чтения, а также позволяет использовать повторно общие участки кода. Одним из примеров является форма для создания или редактирования пользователей. Обоим действиям #new и #edit нужна форма для ввода пользовательских реквизитов, и чаще всего эти формы идентичны. Поэтому такую форму обычно называют наподобие _user_form.html.erb, а затем вызывают ее из шаблонов new.html.erb и edit.html.erb

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

    # app/views/users/new.html.erb
    <div class="new-user-form">
      <%= render "user_form" %>
    <div>

Следует обратить внимание на пару особенностей синтаксиса. Файл парциала представления _user_form.html.erb начинается с нижнего подчеркивания, но вызывается с использованием основной части своего имени, как user_form в примере выше.

Если в имени парциала не указана папка, то Rails будет искать файл только в той папке, откуда он был вызван, то есть app/views/users. Иногда имеет смысл иметь общие парциалы для представлений, находящихся в разных контроллерах. В таком случае можно создать папку app/views/shared, а затем рендерить их используя <%= render "shared/some_partial"%>.

Передача локальных переменных в парциалы

С помощью парциалов можно сделать многое, но мы здесь не будем вдаваться во все детали, кроме, пожалуй, передачи в них переменных. Парциал имеет доступ ко всем переменным вызывающего его представления, но НЕ полагайтесь на них! Что, если парциал используется различными контроллерами, которые используют различную структуру переменных экземпляра? Если парциал постоянно ожидает такую переменную как @user - то это пример плохого кода. Это значит, что вы должны явно передавать в парциал ту переменную, которая необходима в данный момент.

В примере выше, вы наверняка захотите передать в парциал переменную @user, чтобы отрендерить нужную форму. render - это обычный метод, и он позволяет передавать хэш опций. Одной из таких опций является ключ :locals, который содержит передаваемые переменные. И мы можем изменить код таким образом:

    <%= render "shared/your_partial", locals: { user: @user } %>

Для использование переменной в парциале, просто отбрасываем @ и используем обычную переменную.

Неявные парциалы

Как обычно, Rails предоставляет возможность краткой записи для повседневных задач. Одной из них является рендеринг объектов модели, например User или Post. Если вам нужен список всех пользователей, то в app/views/users/index.html.erb вы можете написать код HTML и ERB для многократного отображения имени, фамилии, e-mail и т.д., или же оформить такой код в виде цикла each.

Но лучшим путем обычно бывает использовать собственный парциал _user.html.erb, чтобы его можно было также использовать и в других случаях. Обычно это выглядит так:

    # app/views/index.html.erb
    <h1>Users</h1>
    <ul>
      <% @users.each do |user| %>
        <%= render "user", locals: {user: user} %>
      <% end %>
    </ul>

И в вашем парциале:

    # app/views/_user.html.erb
    <li><%= "#{user.first_name} #{user.last_name}, #{user.email}" %></li>

Наличие в парциале всего одной строчки может показаться странным, но, поверьте, это ненадолго, так что не стОит заморачиваться по этому поводу.

Если это обычный путь, каков же магический путь Rails? Прочто укажите объект User для рендеринга напрямую, например:

    # app/views/index.html.erb
    <h1>Users</h1>
    <ul>
      <% @users.each do |user| %>
        <%= render user %>     <!-- НАМНОГО меньше кода -->
      <% end %>
    </ul>

Rails в этом случае ищет в текущем каталоге файл _user.html.erb и автоматически передает в него переменную user.

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

    # app/views/index.html.erb
    <h1>Users</h1>
    <ul>
      <%= render @users %>
    </ul>

Здесь Rails не только ищет в текущем каталоге файл _user.html.erb и автоматически передает в него переменную user, а также перебирает каждого пользователя в коллекции @user. Все просто.

Методы-помощники

Из представлений вы можете вызывать не только метод рендеринга. Есть немало методов-помощников, доступных вам из представлений. Вот несколько из наиболее известных:

#link_to

`link_to' создает гиперссылку. Вместо:

    <a href="<%= users_path %>">See All Users</a>

Вы пишете:

    <%= link_to "See All Users", users_path %>

И это путь Rails. Напомним, что users_path создает относительный URL /users, в то время как users_url используется для получения полного URL http://www.yourapp.com/users. В большинстве случаев это различие неважно, так как браузер успешно обрабатывает оба варианта, но вы должны понимать разницу.

Ресурсные тэги/Asset Tags

Как вы видели ранее в макете приложения, Rails предоставляет методы-помощники, которые создают HTML ссылки на файлы CSS или Javascript. Аналогично вы можете подтягивать в свое приложение и файлы изображений. Эти методы называются ресурсными тэгами. С понятием "Asset Pipeline" мы познакомимся немного попозже, но в основном эти тэги находят нужные файлы по их имени и создают необходимый тэг HTML.

    <%= stylesheet_link_tag "your_stylesheet" %>
    <%= javascript_include_tag "your_javascript" %>
    <%= image_tag "happy_cat.jpg" %>

Создаст что-то вроде:

    <link data-turbolinks-track="true" href="/assets/your_stylesheet.css" media="all" rel="stylesheet">
    <script data-turbolinks-track="true" src="/assets/your_stylesheet.js"></script>
    <img src="/assets/happy_cat.jpg">

примечание: в режиме "production", ваши CSS и javascripts будут объединены в отдельные файлы, и не волнуйтесь, если они будут называться наподобие /assets/application-485ea683b962efeaa58dd8e32925dadf

Формы

В Rails существует несколько различных помощников (хелперов), создающих формы, и мы ими воспользуемся в последующих уроках.

Ваши задания

Теперь, когда вы получили представления об основах, настало время вникнуть в детали. Материал по ссылке ниже начинается с работы контроллера, где вы должны указать, КАКОЕ представление вы должны отрендерить. Вторая же половина больше относится к работе с представлениями.

  1. Прочтите главу о макетах и рендеринге, с раздела 1 до 3.4. Не заостряйте внимание на начале материала, где рассказывается о множестве опций, которые можно передать функциям - необходимо просто знать что они есть, но запоминать их все нет необходимости. Обычно, если вам что-то понадобится в работе, бывает достаточным погуглить материал, а на сайте Stack Overflow найти нужную вам опцию.

Заключение

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

Дополнительные ресурсы

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

Поделиться уроком: