Перед вами - ознакомительный материал из книги "Мир Rails". Полную версию книги можно приобреcти на сайте hasBrains.

Книга "Мир Rails"

Содержание

Как читать эту книгу

Проще всего объяснить принцип — продемонстрировав пример (именно так мы и будем поступать в дальнейшем). В этой книге мы будем использовать в качестве примера интернет-магазин, над которым мы якобы работаем. В отличие от других книг, этот пример никогда не будет завершен и более того, его разработка на протяжении книги не будет последовательной. Я просто буду говорить — "в нашем интернет магазине" и дальше приводить пример задачи, которую надо решить или пример кода, который нужно написать. Мы не будем держать в памяти и учитывать все детали интернет-магазина или все те изменения, которые мы внесли в него до этого. В то же время, поскольку интернет-магазин является довольно понятным большинству пользователей (и, полагаю, всем моим читателям) приложением, его общая структура, задачи и концепции известны и понятны всем. Именно поэтому мне не нужно будет тратить время на объяснение предметной области1 и логики и я смогу сосредоточиться на объяснении того, как решить конкретную известную всем задачу (скажем, добавление товара в корзину) с помощью Ruby On Rails.

Сама книга условно разделена на три части. В главах с 1-ой по 3-ю вы можете "откинуться на спинку кресла" и попытаться "впитать" теоретический материал настолько, насколько это возможно. С 3-ей по 6-ую главу я буду рассказывать о самых важных частях Rails — моделях, контроллерах и views. К сожалению, изучать их последовательно и по отдельности невозможно. Моя рекомендация будет следующей: после завершения 3-ей главы попробуйте читать 4-ую, 5-ую и 6-ую — одновременно, по немногу продвигаясь вперед. Это поможет вам не потерять из виду общую картину архитектуры MVC и окончательно не запутаться. Наконец, с 7-ой главы вы можете продолжить читать в обычном режиме.

Чтобы прочесть и понять эту книгу, вам потребуется как минимум знание языка Ruby.

1 Предметная область — все, что имеет отношение к задаче, ради которой делается приложение. Например, если бы мы разрабатывали приложение для авиадиспетчеров, то предметная область называлась бы "регулирование воздушного движения". Если бы мы делали интернет-банк, то предметная область называлась бы "обслуживание клиентов банка". В нашем случае предметной областью будет "интернет-торговля".

Соглашения, принятые в книге

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

  • Ruby, html, css и другой код, а также команды для терминала могут быть вынесены в отдельный блок, например так:

    item1.name = "Porsche" item1.name = "A really fast car" item1.price = 3000000
  • Код также может встречаться прямо внутри предложения; тогда он может выглядеть так: item1 = Item.last
  • Символ #, который используется внутри блока с кодом внутри предложения — означает не комментарий, а инстансный метод. Например, если речь в предложении идет о классе Item, то я могу написать "и затем вам нужно вызвать на объекте Item метод #save" или я могу также написать "и затем вам нужно вызвать метод Item#save", что будет означать ровно то же самое. Это повсеместно принятое в литературе по Ruby обозначение инстансных методов. Внутри большого блока кода, символ # будет означать комментарий.
  • Аналогично предыдущему соглашению, точка . означает метод классад Например, я могу написать "после того как вы вызовите метод Item.create...".
  • Внутри блоков с кодом вам может встретиться подобное выражение:

    @item.id #=> 1 Это стандартный способ, принятый в документации Ruby-библиотек для того, чтобы прямо рядом с исходным кодом показать, каков будет результат выполнения этого кода. Т.к. символ # в Ruby означает комментарий, то все, что следует за ним — игнорируется программой и предназначено исключительно для глаз программиста. В данном случае я хотел показать, что если вызвать на переменной @item метод #id, то он вернет значение 1.
  • Так как некоторые файлы могут состоять из большого количества кода, неразумно было бы приводить его целиком каждый раз. Я буду использовать три точки ..., когда я подразумеваю наличие какого-либо кода в том месте, где указаны эти точки. Например:

    class Item < ActiveRecord::Base ... validates :price, numericality: { greater_than: 0 } ... end

Глава 1. Архитектура веб-приложения

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

Что называют веб-приложением?

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

Рассмотрим пример сайта организации X. На сайте есть несколько страниц, например "О компании", "Контакты" и "Наши клиенты". Страницы связаны между собой ссылками, кликнув на которые пользователь может перейти к интерейсующей его странице. На сайте есть несколько фотографий и email для связи с организацией. Такой сайт не является веб-приложением: технически пользователь действительно посылает данные на сервер — он отправляет серверу url интересующей его страницы и сервер посылает назад в браузер желаемую страницу. Однако помимо этого взаимодействия ничего, на самом деле, не происходит. Такие сайты обычно называют статичными сайтами, потому что все, что они позволяют делать — смотреть страницы, которые никак не изменяются с прошествием времени.

Перейдем к сайту организации Y. Этот сайт позволяет пользователю зарегистрироваться через специальную форму с двумя полями: "email" и "пароль". После регистраци пользователь будет видеть свой email, например в верхнем правом углу сайта, и у него появится возможность заказывать и оплачивать товары, производимые организацией Y. Чтобы уметь это делать, сайт должен знать как поступать с приходящими от пользователя данными: например, куда сохранять логин и пароль и сведения о заказах; как проверить, что введенный пользователем email действительно похож на email; как дать возможность пользователю заплатить за товар с помощью его кредитной карты. Такой сайт можно назвать веб-приложением. Но, конечно же, обычные пользователи вряд ли станут называть Вконтакте или, скажем, Википедию — веб-приложением. Тем не менее, каждый из этих сайтов требует логики для обработки вводимых пользователем данных, которая реализуется с помощью того или иного языка программирования. И, значит, данные сайты являются программами, т.е. приложениями.

Однако даже профессионалы не всегда соглашаются с таким значением термина веб-приложение. В последние несколько лет на рынке стало появляться большое количество веб-приложений, которые заменяют привычные нам десктопные приложения и работают таким образом, что пользователю не приходится перезагружать страницу в браузере или кликать по каким-то ссылкам, чтобы получить больше информации (об этом чуть позднее в разделах Чем веб-приложение отличается от других видов приложений? и Одностраничные веб-приложения и почему Rails не подходит для их создания). Именно потому, что эти приложения ведут себя как десктопные приложения, а Вконтакте и Википедия — нет, некоторые разработчики продолжают считать последние недо-веб-приложениями. Мое мнение заключается в следующем: если потребовалось написать код (на любом языке программирования), чтобы сайт заработал, то перед нами веб-приложение.

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

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

Чем веб-приложение отличается от других видов приложений?

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

Ключевой вопрос для практически любого приложения — где хранить данные, которые передал ему пользователь? В отсутствие инернета этот вопрос решался просто: хранить локально. В виде файла, формат которого определяет автор приложения; либо записывать в локальную базу данных, формат которой определялся разработчиком этой СУБД. Далее, даже без интернета, перед пользователями часто вставал вопрос обмена данными с другими компьютерами и решался он с помощью внешних накопителей: записываем файл на диск, несем другу, он копирует его себе.

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

Однако сразу же становится очевидно, что очень многие задачи, которые выполняет такой софт не требуют доступа к ресурсам локальной машины. Например, Amazon.com конечно мог бы создать приложение для Windows и заставить всех пользователей скачать его, но в этом не было бы никакого смысла — на каждой машине, в том числе под управлением других ОС, есть какой-нибудь браузер, в который они могут загрузить веб-приложение и продавать товары через него. В этом случае, пользователю не нужно скачивать и устанавливать софт на собственный компьютер (многие не знают, как это делается или не имеют доступа) — достаточно набрать адрес в браузере. Кроме того, у вас сразу отпадает вопрос обновления старых версий приложения. Если старая версия вашего десктопного приложения (в данном контексте принято называть его клиентом) не поддерживает новую версию вашего ПО на сервере, то вам придется либо огорчить пользователя, либо ждать пока он решит обновиться (что может никогда не произойти) и поддерживать две версии серверного ПО. В случае с веб-приложением, "обновление" произойдет как только пользователь обновит страницу или снова зайдет на сайт.

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

Вообще эта особенность браузера — не давать доступ к системе — очень важная вещь. Эта концепция называется sandbox (песочница) и это является большим преимуществом веб-приложений. Пользователь, скачавший приложение и запустивший его на своей машине, подвергает себя куда большей опасности, потому что, по сути, скачанный софт получает доступ ко всем файлам пользователя (эту проблему частично решают на мобильных устройствах, предварительно уведомляя пользователя о том, к каким частям системы будет иметь доступ приложение). Веб-приложение работает только внутри браузера и без ведома пользователя не может получить доступ ни к какой информации на жестком диске компьютера. Таким образом, веб-приложения, с точки зрения обычного пользователя, по умолчанию гораздо безопаснее. Безусловно, есть вероятность что в будущем, браузеры будут позволять веб-приложениям запрашивать больше прав для доступа к локальным ресурсам пользователя (по аналогии, опять-таки, с мобильными приложениями), но на данный момент это не так...

***

Глава 3. Преждем чем начать: знания, которые вам понадобятся

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

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

Хорошее знание языка Ruby и объектной модели

Очень часто люди берутся изучать фреймворк Rails без знания даже основ Ruby. Почему это происходит? Я полагаю, потому что очень распространен миф о "волшебстве" Rails и многим кажется, что просто установка фреймворка уже решит за вас задачу создания веб-приложения. Это не так. Основная проблема с которой, на мой взгляд, сталкиваются новички разбирающиеся в Rails без знания Ruby — это, условно выражаясь, невозможность решать проблемы, которые не были освещены в скринкасте "как сделать блог за 15 минут".

Если говорить более абстрактно, то без знания языка Ruby у вас отсутствует возможность свободно мыслить. Как если бы вы учили иностранный язык только одним просмотром сериалов, то вы бы знали заранее заготовленные и знакомые фразы, но не умели бы четко и свободно выражать все свои мысли в той форме, которая характерна именно для вас — для этого требуется знание грамматики. Или как если бы вы пытались написать песню выучив основные аккорды на гитаре — песню, конечно, написать можно, но ничего нового и оригинального вы скорее всего не привнесете, потому что вы совсем не знаете нотную грамоту, гармонию и композицию, и, следовательно, у вас отсутствует возможность учиться на огромном количестве музыкального материала. Многие люди, чему бы они не начинали учиться, покупаются на этот миф, что главное в этом деле — "душа". Избегайте этого мифа. Он опасен, потому что в итоге вы ничему не научитесь и вас никто не будет воспринимать всерьез.

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

Я хотел бы особо подчеркнуть этот момент: если вы копируете, генерируете или читаете чужой код или даже если вы пишите его сами — убедитесь, что вы понимаете его на 100%. Убедитесь что вы понимаете каждое слово этого кода и почему оно стоит именно в этом месте. Если у вас в чем-то возникают сомнения, не говоря уже о случаях, когда вы понятия не имеете, что означает эта строка кода — прекратите любую дальнейшую работу и разберитесь в коде.2

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

  • Объектно Ориентированное Программирование: что такое классы и объекты и зачем они нужны
  • Методы: публичные и приватные методы, вызов методов, аргументы, возвращаемые значения
  • Переменные: локальные, инстансные (переменные экземпляра), область видимости переменных, переменные класса, глобальные переменные, константы
  • Операторы: присваивания, сравнения, арифметические, логические
  • Блоки: что такое замыкание (closure), самые распространные методы с блоками, как написать свой метод принимающий блок.
  • Основные типы данных3: строки, числа (Integer, Float), дата и время, символы и чем они отличаются от строк
  • Управляющие конструкции: if-else, циклы while и until

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

1 Генерируют чаще всего с помощью т.н. скаффолдинга (scaffolding) — об этом я поговорю отдельно в разделе Как не нужно программировать на Ruby On Rails.
2 Начать разбираться в строке кода можно попытавшись ее немного видоизменить в соответствии с той теорией, которая у вас есть в голове, относительно того, что значит и как работает этот код. После того, как вы измените ее, следите за поведением программы и попытайтесь понять в чем тут дело. Или откройте irb и исследуйте изолированную проблему в ruby-консоли. В крайнем случае, вы всегда можете обратиться за помощью к другим людям — как это сделать рассказано в главе Что дальше: как разбираться в проблемах и кому задавать вопросы?.
3 Вернее будет сказать — классы, представляющие типы данных.

Архитектура MVC

MVC — это т.н. называемый шаблон программирования1, который использовался с 80-х годов для создания программ с графическим интерфейсом. Этот шаблон придумал программист на языке Smalltalk которого звали Trygve Reenskaug, в далеком 1979-ом.

Основная идея заключается в том, что ваша программа разделена на три части, каждая из которых представлена буквой в этой аббревиатуре: M — Model (модель), V — View (представление), C — Controller (контроллер). Ниже я расскажу зачем нужна каждая из частей.

Модель

Модели — это некие объекты содержащие в себе всю информацию о предметной области приложения. Например, если вы создаете интернет-магазин, у вас могут быть такие модели как Item (товар), User (пользователь), Cart (корзина) и Order (заказ). В Rails-приложении каждая модель представляет из себя отдельный класс, с экземплярами (объектами) которого мы будем в дальнейшем работать. Например, мы могли бы создать объект класса Item и задать для него разные свойства, например #price, #weight и #name.

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

На практике, Rails-приложения нечасто имеют десктопную версию и, скорее всего, код моделей не используется там повторно (потому что десктопные версии, обычно, пишутся не на языке Ruby). Мы тем не менее, сможем отдельно использовать наши модели для манипуляции данными в нашем приложении, когда мы будем изучать Rails-модели и "общаться" с ними через rails-консоль (подробнее об этом читайте в главе Модели, ActiveRecord и взаимодействие с БД)...

***

Глава 5. Модели, ActiveRecord и взаимодействие с БД

Основы моделей в Rails

Мы уже касались понятия MVC в разделе Архитектура MVC главы Преждем чем начать: знания, которые вам понадобятся. Здесь я постараюсь подробнее раскрыть тему моделей и на примерах показать для чего создается модель в Rails. В целом, можно сказать, что разработка Rails-приложения начинается с моделей, а вернее с решения о том, что должно стать моделью в вашем приложении. Модели — это мозг вашей программы без которого программа не сможет выполнять никаких полезных функций.

Как решить, что должно стать моделью?

Рассмотрим типичный интернет-магазин. Какой функционал в нем должен присуствовать? Пользователи должны иметь возможность просматривать категории и товары в них, добавлять товары в корзину, оформлять заказы и оставлять отзывы о конкретных товарах. Чтобы решить, какие модели нужны в нашем Rails-приложении, необходимо внимательно посмотреть на предыдущее предложение и выделить в нем существительные, имеющие отношение к предметной области: пользователи, категории, товары, корзина, заказы и отзывы. Именно для этих понятий в нашем приложении и будут существовать модели и, в дальнейшем, они будут уметь взаимодействовать друг с другом. Можно думать о приложении как о real-time стратегии, где модели представляют из себя различные юниты, появляющиеся и исчезающие на карте сражений.

При разработке приложения, вам не следует создавать все возможные модели сразу и мучаться, не забыли ли вы какую-то другую модель. Напротив, сначала нужно ограничиться минимальным количеством моделей и постепенно, по мере продвижения разработки, добавлять новые. Идеально сначала добавить только одну единственную модель — ту, которая, по вашему мнению, является ключевой для вашего приложения — и начать заполнять ее кодом. Очевидно, что в нашем случае такой моделью является Товар. После добавления этой модели в наше приложение мы начнем постепенно писать ее функционал — валидации, коллбэки, методы и другие части кода.

Хотелось бы отметить, что когда я говорю о постепенном добавлении моделей в приложение, я вовсе не имею в виду, что вы будете выкладывать это приложение на продакшен в неготовом виде (хотя и такой подход тоже возможен). Предположим, ваш клиент дает вам срок разработки интернет-магазина — 1 месяц. Тогда вы можете запланировать, что в первые две недели вы добавите модели Товар, Категории и Пользователи; в следующие две недели вы запрограммируете функционал для моделей Корзина и Заказы; и только в конце месяца займетесь отзывами.

Как правильно назвать модель?

Название моделей в Rails должны представлять из себя существительные, или словосочетания заканчивающиеся на существительные — естественно на английском языке и обязательно в единственном числе. Таким образом, для наших слов, которые мы "вытащили" из предложения описывающего функционал интернет-магазина, мы могли бы создать следующие модели: User (пользователь), Category (категория), Item (товар), Cart (корзина), Order (заказ), Review (отзыв). В дальнейшем, в нашем магазине могут произойти изменения и нам понадобится разделять товары на физические и виртуальные — в этом случае, по соглашению именования классов в Ruby, мы бы добавим две модели с именами RealItem и VirtualItem, т.е имя каждой модели будет состоять из слов в CamelCase1.

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

Примеры именования моделей в Rails

Неверный вариант Возможный преемлемый вариант
Users User
ItemThatIsReal RealItem
Virtualitem VirtualItem
Ordering Order

Как создать модель?

Выполните в терминале команду:

rails g model [model_name] Естественно, вместо [model_name] необходимо подставить название вашей модели. Причем в т.н. snake case2. Например, вот две команды, которые создадут модели Item и VirtualItem соответственно:

rails g model item rails g model virtual_item Каждая из команд запустит генератор, который создаст два файла: файл с миграциями (на него мы посмотрим в разделе Миграции, атрибуты в моделях и что такое ORM) и файл с моделью. В нашем случае, когда мы создаем модель Item, это будет файл app/models/item.rb. Открыв этот файл, можно будет увидеть следующую картину:

class Item < ActiveRecord::Base end Как видите, в файле ничего нет, кроме этих двух строк (возможно будет еще закомментированная строка, начинающаяся на attr_accessible — к этому мы вернемся позже), то есть генератор не сделал за нас слишком много работы. Это хорошо, потому что, как вы помните, нам необходимо понимать каждую строку кода в нашем приложении...

***

Глава 6. Контроллеры и ресурсы

Эта глава будет в основном посвящена контроллерам в Rails — связующему звену между views и моделями. Нам, однако, не удастся обойтись без примеров форм, которые пользователь будет отправлять из браузера и данные из которых будут поступать в тот или иной контроллер. Чтобы научиться работать с контроллерами, нам придется параллельно знакомиться и с views. Мы не будем затрагивать views слишком глубоко — им посвящена отдельная глава, но простейшие шаблоны вы научитесь создавать уже в этой главе. Для изучения этой главы вам понадобится открытый браузер и базовые знания html. И, конечно же, запущенное терминале Rails-приложение1.

1 Если вы уже успели это забыть, то напоминаю, что Rails-приложение запускается командой rails s, если вы находитесь в папке с приложением.

Типы HTTP-запросов

Прежде чем продолжить, вынужден сделать небольшое отступление, чтобы рассказать про http-глаголы и типы запросов. Как вы, надеюсь, понимаете, когда вы щелкаете по ссылке, отправляете форму или даже набираете адрес в адресной строке браузера и нажимаете клавишу Enter — браузер делает запрос на сервер. Браузеры могут делать два разных типа запросов на сервер — GET и POST. Собственно, эти два слова и называют "глаголами" — именно они и определяют тип запроса. Теоретически, GET запросы предназначены для получения данных с сервера, а POST запросы — для отправки данных. На практике сервер, конечно же, всегда что-нибудь отвечает, а браузер всегда что-нибудь посылает (например тот же url). Чтобы не усложнять картину, можно подразумевать, что POST запросы предназначены для тех случаев, когда мы пытаемся отправить на сервер больше данных, чем хотим получить — например, когда мы добавляем новый товар в магазин мы отсылаем на сервер POST запрос с данными о новом товаре и, возможно, его изображением, а назад получаем короткое сообщение о том, что товар создан.

На самом деле, документация к протоколу HTTP описывает не только GET и POST запросы, но и еще несколько других типов — в частности PUT и DELETE. Что они означают мы узнаем немного позже, в разделе CRUD и доступ к экшенам в RESTful контроллере. Сейчас же скажу, что браузеры их не поддерживают, но авторы Rails нашли способ обойти это ограничение и Rails успешно понимает эти типы запросов.

Чем занимается и из чего состоит контроллер?

Контроллер — это связущее звено между моделью и тем, что пользователь видит в браузере, то есть представлением (views). Когда пользователь заполняет форму и нажимает кнопку "создать товар", браузер отправляет запрос на сервер, в наше Rails-приложение. В зависимости от того, на какой url был отправлен запрос, а также какой http-глагол был использован (GET, POST, PUT, DELETE) — приложение решает какой контроллер и какой его экшен ответственен за то, как поступить с запросом. А дальше, в самом контроллере, мы сможем разобрать пришедшие от пользователя данные и начать на их основе взаимодействовать с моделями нашего приложения — точно так же, как мы делали это в rails-консоле, в главе посвященной моделям.

Сам контроллер в Rails-приложении представляет из себя специальный класс, название которого заканчивается на Controller и который наследуется от класса ApplicationController. Все контроллеры в вашем приложении будут находится в папке app/controllers и название файлов каждого из контроллеров идентично названию класса в нем содержащегося — только записанного в snake_case.

Как правило контроллеры в Rails-приложении соответствуют существующим моделям. Например, если в нашем приложении есть модели Item и User, то скорее всего, у нас в приложении будут и контроллеры ItemsController и UsersController (обратите внимание на то, что в большинстве случаев первое слово в названии контроллера идет во множественном числе — почему это так мы сможем понять немного позже). Однако это вовсе не является правилом. В нашем приложении могут существовать модели, для которых не будет контроллера, например нам вряд ли понадобится отдельный контроллер для модели Position, т.к. необходимые операции по добавлению и удалению товаров из корзины будет выполнять контроллер CartsController. В то же время, в приложении может существовать контроллер, который не имеет отношения к какой-либо модели: например для администраторов магазина можно было бы создать контроллер SettingsController, который бы позволял изменять различные настройки магазина и сохранять их напрямую в специальный текстовый файл с настройками.

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

rails g controller items После этого, если вы откроете файл app/controllers/items_controller.rb вы увидите там следующие две строки кода:

class ItemsController < ApplicationController end Пока что наш контроллер полностью пустой.

Чтобы сделать его хоть немного полезным, мы могли бы добавить в него экшен — экшеном в контроллерах Rails называют все публичные методы, потому что любой публичный метод в контроллере можно назначить ответственным за тот или иной запрос, приходящий от пользователей. Например, мы могли бы создать экшен #hello вот так:

class ItemsController < ApplicationController def hello # Следующая строка выведет в браузер приветствие # (пока никакого html, просто текст) render text: "This is ItemsController speaking, hello!" end end В следующем разделе мы посмотрим, как нам с помощью браузера попасть на этот экшен и увидеть на экране приветствие (пока у вас этого сделать не получится).

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

С точки зрения языка Ruby — класс ItemsController — это такой же класс, как и, например, модель Item. Однако экземпляры этого класса создает сама Rails, внутри своего исходного кода. В то же время, мы будем постоянно создавать много разных экземпляров наших моделей самостоятельно. Не удивляйтесь этому факту и пусть вас не вводит в заблуждение то, что формально вы лично нигде не вызываете ItemsController.new — повторюсь, это делает сама Rails, в нужном ей месте. Ваша задача, как прогаммиста — описать контроллер, наполнить его экшенами и другим необходимым кодом, который затем будет выполняться, когда поступит соответствующий запрос.

URL и обращение к экшенам контроллера, routes

Как уже упоминалось ранее, Rails знает в какой контроллер и в какой экшен направлять каждый запрос, который приходит из браузера. Вернее сказать, Rails будет об этом знать, когда мы объясним это в специальном файле, который называется config/routes.rb. По-русски обычно так и говорят: "рауты"1. Этот файл как раз и отвечает за назначение url-ов и типов http-запросов тому или иному контроллеру.

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

StoreApp::Application.routes.draw do # Здесь будет много закомментированных строк end Именно внутри блока, который передается методу #draw нам и предстоит писать инструкции. Для начала поместим туда следующую инструкцию:

StoreApp::Application.routes.draw do match ':controller(/:action(/:id))' end Данная инструкция по умолчанию добавлялась в каждое новое Rails-приложение в старых версиях Rails, пока авторы фреймворка не решили, что это нежелательный способ работы с приложением и что нам нужно переходить на RESTful контроллеры. Нам же, как новичкам в Rails, эта строка поможет разобраться с основами работы контроллеров. После того, как мы разберемся с основами и перейдем к RESTful контроллерам — можно смело удалять эту строку из файла и заменять ее на инструкции по созданию ресурсов2...