Ruby on Rails шаг за шагом. #3 Контроллер и Вид

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

    • app: динамическая часть вашего приложения
      controllers: интерфейс и деловая логика
      helpers: код для поддержки Видов
      models: объекты Модели, соотносящиеся с БД и используемые в приложении
      views: шаблоны для отсылки удаленному пользователю
      layouts: файлы макетов страниц
    • config: настройки среды, базы данных и приложения
      enviroments: конфигурации, относящиеся к средам
      initializers: конфигурационные файлы, обрабатывающиеся при запуске сервера
    • db: схема базы данных в виде миграций Active Record
    • doc: документация вашего веб-приложения
    • lib: библиотеки Руби, относящиеся к приложению
    • log: файлы логов
    • public: статическая часть вашего приложения
      stylesheets: CSS файлы
      javascripts: файлы JavaScript
      images: файлы изображений
    • script: Shell-скрипты для управления проектами RoR
    • test: код и данные для тестирования вашего приложения
      fixtures: даные, загружаемые в БД при тестировании
      functional: фунциональные тесты для проверки Контроллеров
      integration: интеграционные тесты
      unit: Юнит-тесты для проверки Моделей
    • tmp: здесь Rais хранит временные данные
    • vendor: внешние библиотеки, используемые приложением
      plugins: плагины RoR

    Доброй традицией стало “Hello World” в качестве примера работы любого ЯП или движка. Что ж, давайте сделаем страничку, которая будет приветствовать нас. Мы знаем, что приложение на RoR должно состоять из трех компонентов: Вида, Контроллера и Модели. Сказать привет – это просто, достаточно передать браузеру HTML-код. Несложно догадаться, что HTML должен содержаться в Виде, однако RoR не позволяет создавать виды напрямую, так как Вид должен быть непосредственно ассоциирован с Контроллером. Чтобы сгенерировать что-нибудь в RoR, нужно идти в командную строку (мы уже знаем, как это делается) и переместиться в папку приложения. Тут мы и командуем:
    ruby script/generate controller Hi index

    script/generate – это Shell-скрипт generate в папке script, написанный на Руби, поэтому запускать скрипт нужно через интерпретатор (для этого мы добавила ruby в начале команды). Так же мы передали скрипту два аргумента: controller определяет, что необходимо сгенерировать код Контроллера, в данном случае он будет назваться Hi – это говорит второй аргумент. А index в конце команды привяжет к контроллеру Вид index, что, собственно, нам и требовалось. Немого подождем, и вот что выдаст нам скрипт:
    exists   app/controllers/<br>exists   app/helpers/<br>create   app/views/hi<br>exists   test/functional/<br>create   app/controllers/hi_controller.rb<br>create   test/functional/hi_controller_test.rb<br>create   app/helpers/hi_helper.rb<br>create   app/views/hi/index.html.erb

    Строки, начинающиеся с exists, показывают папки и файлы, который генератор хотел создать, но они уже были на месте. Зная о структуре папок, мы уже можем сказать, что были созданы: папка hi в Видах, Контроллер, шаблон для создания тестов, хэлпер и файл Вида index.html.erb (формат .html.erb – это сочетание HTML и кода Руби).

    Теперь index стал доступен для приложения. Давайте запустим сервер и заглянем в http://127.0.0.1:3000/hi/:

    image

    Немногословно, но страничка подсказывает нам, что файл находится в app/views/hi/index.html.erb. Открыв его, вы заметите, что в коде даже нет базовой структуры HTML. Давайте немного дополним файл и приведем его в более порядочный вид:
    <html>
    <
    head><title>Hi Habrahabr!</title></head>
    <
    body>
    <
    h1>Hello!</h1>
    <
    p>Это приветствие прибыло из app/views/hi/index.html.erb</p>
    </
    body>
    </
    html>

    Сохраним файл и обновим страничку:

    image

    Наверное, все эти генерации множества папок выглядят достаточно сомнительно для того, чтобы создать заурядную HTML страничку. Для того, чтобы начать использовать силу RoR, поработаем с Контроллером app/controllers/hi_controller.rb. Вот, что в нем находится:
    class HiController < ApplicationController
    def index
    end

    end

    Мы с вами уже знаем Руби, поэтому кодом нас не испугаешь: объявлены класс HiController (заметим, что название класса было сгенерировано на основе имени Контроллера — это CoC и мы еще будем говорить почему и зачем), который является потомком класса ApplicationController и пустой метод index. Давате пофантазируем с методом, задавая в нем переменные и отображая их в Виде. Для этого в RoR используются переменные экземпляра (те самые, который начинаются с @):
    class HiController < ApplicationController
    def index
        
    @habr = 'Habrahabr'
        
    @message = 'Это сообщение пришло из Контроллера'
    end
    end

    Соответственно отредактируем Вид, чтобы показать переменные:
    <html>
    <
    head><title>Hi <%= @habr %>!</title></head>
    <
    body>
    <
    h1>Hello!</h1>
    <
    p>Это приветствие прибыло из app/views/hi/index.html.erb</p>
    <
    p><%= @message %></p>
    </
    body>
    </
    html>

    И тут мы видим, как код Руби внедряется в HTML. Для вывода значения переменной в HTML-код мы используем тэги <%= … %> – это так называемое выражение (expression).

    Для того, чтобы получить текущее время в Руби используется метод Time.now. Достаточно вставить в HTML <%= Time.now %>, однако стоит использовать преимущества MVC и делать расчеты в Контроллере. Попробуйте “считать” время в Контроллере и отбразить его на странице Вида.

    Логика в Виде


    Мы также можем добавлять некоторую логику в файлы Вида, например, чтобы создавать списки, мы можем использовать итераторы. Допустим, мы хотим вывести переменную @message пять раз в параграфах. Мы знаем, как сделать это на чистом Руби:
    5.times do
    puts "<p> #{@message} </p>" # немного неверно, но неважно
    end

    Осталось только переделать код в формат .erb, получается даже несколько проще:
    <% 5.times do%>
    <p><%= @message %></p>
    <% end %>
    puts заменили тэги <%= … %>. А когда вывод кода нам не нужен мы просто опускаем = в тэгах. Вот что у нас получилось

    image

    Как это работает?



    Когда запускается код, RoR интерпретирует запрос 127.0.0.1:3000/hi/ как вызов Контроллера Hi. У RoR есть редактируемый список правил роутинга запросов, по умолчанию первая часть запроса — имя Контроллера, вторая — метод в нем. Опять же, по умолчанию вызывается метод index, поэтому мы не уточняли метод в запросе. Метод определяет необходимые базовые переменные. На этом работа Контроллера закончена и RoR передает данные в Вид. Как он знает, в какой Вид нужно передать данные? Работают conventions — магия договоренностей об именовании.

    Эпилог


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

    Похожие публикации

    Комментарии 20
      0
      >Чтобы создать что-нибудь в RoR, нужно идти в командную строку

      Смущает слово «нужно»? А ручками создать файлы нельзя?
        0
        Эмм… Здесь я имел в виду что-то серьезное :) вроде контроллера, модели. Сейчас поправлю
          0
          Ну да, файл контроллера из 5-ти строк или вида из двух это очень серьезно и практически невозможно создать ручками :)
            0
            Да тут дело скорей не в том что сложно, но зачем, если есть полуавтоматические средства? А ручками все потом надо подкрутить и радоваться, что генераторы избавили от ненужной рутины :)
              0
              Ну, как вариант, из одного проекта можно (или нельзя?) просто скопировать файлы в другой, а не генерировать, а потом копипастить их содержимое.
          +2
          > А ручками создать файлы нельзя?

          Правило Генерации: «Избегайте ручного ввода кода, при любом удобном случае пишите программы, которые бы писали программы.» (С) «Философия UNIX».
          0
          controllers: интерфейс и деловая логика

          Меня что-то смущает эта сторчка. Деловая логика вроде бы должна в большинстве своём содержаться в модели, а интерфейс (если вы имеете в виду интерфейс пользователя) — в представлении.
            0
            бизнес-логика всегда в контроллере, что вас смущает? Работа с данными в модели. Интерфейс наверное имелся ввиду не пользовательский, а интерфейс доступа к данным, я так понимаю.
              +1
              Бизнес-логика в контроллере — это в корне неверный подход. Разделение: модель — данные, контроллер — логика работы с ними — это заблуждение, сформированное некоторыми туториалами по популярным фреймворкам, в которых такое разделение введено только лишь для простоты объяснения механизма MVC. На самом деле вся бизнес-логика должна размещаться в слое домена (то есть предметной области). Именно объектами этого слоя и манипулируют контроллеры, выполняя второстепенные сервисные действия, такие как создание, поиск и удаление объектов домена, авторизация и проверка данных (это спорно, очень многие относят это тоже к домену). Вообще, чем меньше кода в контроллерах тем лучше. Вся логика должны быть в объектах предметной области. Именно этот слой должен взаимодействовать с моделью данных путём делегирования либо, вообще, сливаться с ней полностью или частично, объединяя логику и механизмы персистивности (Active record).
                0
                Ух ты как круто, а где об этом можно в подробностях почитать?
                  0
                  О чём именно? Если о том как работать с бизнес-логикой то есть отличная книжка Eric Evans Domain-Driven Design. Наверное, в ней не со всем можно согласиться, но читается она очень интересно.
                  +2
                  Не совсем с вами согласен, все зависит от задачи.

              0
              Ну когда же продолжение?
                0
                Сейчас времени маловато… :( Если и буду писать, то в рамках серии капель о Руби или что-то вроде отдельных кусочков инфы о Rails, потому что разжевывать все с нуля получается с трудом :( Вобщем, если поддержите и настоите на продолжении — то, возьмусь снова ;)
                0
                Моя мама говорит, что любое дело надо доводить до конца :) Я Вас морально поддерживаю и даже смог бы предложить посильную помощь. Например, соавторство.
                  0
                  Ну так будет продолжение или нет? :)
                    0
                    для этого мы добавили ruby в начале команды

                    Это нужно только в Windows.
                    Продолжай! Интересно читать.
                    Для новичков будет лучшим руководством.
                      0
                      Давно добавил все статьи в избранное и жду продолжения!
                        0
                        Код во View типа:
                        <% 5.times do%>
                        <%= @message %>
                        <% end %>
                        — плохая практика.
                          0
                          Надеюсь, что продолжение всё же будет.
                          Автору отписал в л.с. вопрос о судьбе серий.

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

                          Самое читаемое