Опубликован: 27.01.2016 | Уровень: для всех | Доступ: платный
Лекция 4:

Rails — приправленный Ruby

Основанная на примерах из Главы 3, эта глава рассматривает некоторые элементы Ruby важные для Rails. Ruby многогранен, но, к счастью, нам нужна относительно малая его часть, чтобы быть продуктивным Rails-разработчиком. Более того, эта малая часть отличается от той, которая вам понадобится в Ruby для обычных задач, поэтому, если вашей целью является создание динамических веб-приложений, я рекомендую изучать Rails первым, собирая биты Ruby на этом пути. Чтобы стать экспертом Rails, вы должны понимать Ruby более глубоко, и эта книга дает вам хорошую основу для развития. Как отмечалось в Разделе 1.1.1, после окончания Rails Tutorial я советую почитать книги о чистом Ruby, такие как Beginning Ruby, The Well-Grounded Rubyist, or The Ruby Way.

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

Причины

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

Когда мы в последний раз видели наше новое приложение, мы только что обновили наши, в основном статические, страницы использовав Rails шаблон для устранения дублирования в наших представлениях, как показано в Листинге 4.1 (который является слегка переформатированной версией Листинга 3.26).

<!DOCTYPE html>
<html>
  <head>
    <title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>
    <%= stylesheet_link_tag "application", media: "all",
                                           "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>
Листинг 4.1. Шаблон сайта Пример приложения.app/views/layouts/application.html.erb

Давайте сфокусируемся на одной строке в Листинге 4.1:

<%= stylesheet_link_tag "application", media: "all",
                                       "data-turbolinks-track" => true %>

Этот код использует встроенную Rails функцию stylesheet_link_tag (о которой вы можете узнать более подробно из Rails API) для включения application.css для всех медиа типов (включая мониторы компьютеров и принтеры). Для опытного Rails разработчика эта строка выглядит просто, но в ней есть по крайней мере четыре Руби идеи которые могут сбить с толку: встроенные Rails-методы, вызов метода без скобок, символы и хэши. Мы раскроем все эти идеи в этой главе.

Помимо того, что Rails поставляются с огромным количеством встроенных функций для использования в представлениях, они также позволяют создавать новые. Такие функции называются хелперы; для того, чтобы посмотреть как создается собственный хелпер, давайте для начала рассмотрим строку с тайтлом из Листинг 4.1:

Ruby on Rails Tutorial Sample App | <%= yield(:title) %>

Этот код опирается на определение заголовка страницы (используя provide) в каждом представлении:

<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
  sample application.
</p>

Но что если мы не предоставим заголовок? Это хорошее соглашение - иметь базовый заголовок, который мы используем на каждой странице, с дополнительным переменным заголовком (тайтлом), если мы хотим быть более конкретными. Мы уже почти достигли этого с нашей текущей схемой, с одним маленьким недостатком: как вы можете видеть, если вы удалите вызов provide в одном из представлений, без специфичного для страницы заголовка полный заголовок будет выглядеть так:

Ruby on Rails Tutorial Sample App |

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

Для решения проблемы отсутствующего заголовка страницы, мы определим кастомный хелпер с названием full_title. Хелпер full_title будет возвращать базовый заголовок, "Ruby on Rails Tutorial Sample App", в случае если заголовок страницы не определен и добавлять вертикальную черту перед заголовком страницы в противном случае (Листинг 4.2).1Если хелпер специфичен для конкретного контроллера, вам следует помещать его в соответствующий файл; например, хелперы для контроллера StaticPages обычно хранятся в app/helpers/static_pages_helper.rb. В нашем случае, мы ожидаем что хелпер full_title будет использоваться на всех страницах сайта и у Rails есть специальный файл хелпера для таких случаев: app/helpers/application_helper.rb

module ApplicationHelper

  # Returns the full title on a per-page basis.
  def full_title(page_title)
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      "#{base_title} | #{page_title}"
    end
  end
end
Листинг 4.2. Определение хелпера full_title. app/helpers/application_helper.rb

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

<title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></title>

на

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

как видно в Листинге 4.3.

<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= stylesheet_link_tag "application", media: "all",
                                           "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>
Листинг 4.3. Шаблон сайта Пример приложения. app/views/layouts/application.html.erb

Для того чтобы заставить наш хелпер работать, мы можем удалить ненужное слово "Home" из Home страницы, позволив ей вернуться к базовому заголовку. Мы сделаем это вначале обновив наш тест с кодом из Листинга 4.4, который обновляет предыдущий тест тайтла и добавляет один тест на отсутствие кастомной строки ’Home’ в заголовке. (Примечание: Если вы выполнили упражнение соотоветствующее Листингу 3.31, вам следует сохранить выражение let определяющее base_title в первом блоке describe.)

require 'spec_helper'

describe "Static pages" do

  describe "Home page" do

    it "should have the content 'Sample App'" do
      visit '/static_pages/home'
      expect(page).to have_content('Sample App')
    end

    it "should have the base title" do
      visit '/static_pages/home'
      expect(page).to have_title("Ruby on Rails Tutorial Sample App")
    end

    it "should not have a custom page title" do
      visit '/static_pages/home'
      expect(page).not_to have_title('| Home')
    end
  end
  .
  .
  .
end
Листинг 4.4. Обновленные тесты для заголовка Home страницы. spec/requests/static_pages_spec.rb

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

Давайте запустим набор тестов чтобы проверить что один тест провальный:

$ bundle exec rspec spec/requests/static_pages_spec.rb

Чтобы получить прохождение набора тестов мы удаляем строку provide из представления страницы как это показано в Листинге 4.5.

<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
  sample application.
</p>
Листинг 4.5. Home страница без кастомного заголовка страницы. app/views/static_pages/home.html.erb

В этой точке тесты должны пройти:

$ bundle exec rspec spec/requests/static_pages_spec.rb

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

Вадим Обозин
Вадим Обозин

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

Акбар Ахвердов
Акбар Ахвердов
Россия, г. Москва
Артём Зайцев
Артём Зайцев
Украина, ДНР