Как стать автором
Обновить

Чат на рельсах

Время на прочтение4 мин
Количество просмотров7.9K
Сегодня мы с вами создадим приложение на Руби на Рельсах, он же Рейлс, он же РоР. (Ruby on Rails, RoR, Rails). Я для краткости буду употреблять выражения «рельсы», «рейлс» или «рор».

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

Хотя это не туториал, а демонстрация возможностей, вы вполне можете повторить всё это на вашей системе. Всё, что вам понадобится, это mysql-сервер, и рельсы версии как минимум 2.0. Единственное отличие от более ранних, в рамках этого примера, это суффиксы шаблонов (.rhtml в первом, .html.erb во втором).

Я выполнял это на Ubuntu Hardy 8.04, но это должно работать на любой платформе, в случае виндовс с очевидными отличиями в виде разделителя в путях.

С сожалением должен констатировать, что админы Хабра так и не потрудились обеспечить нормальный ввод неэкранированного ХТМЛ и СГМЛ-кода (да и экранированного тоже: попробуйте ввести «меньше»-!DOCTYPE...), поэтому весь код, который нужно занести в файлы проекта, я привожу в виде фоток, так что вам придётся перебивать код вручную, если пожелаете это повторить. С другой стороны, обещаю, что никакой файл не выходит за пределы стандартного терминала 80x25, так что работы не так много. Опять же перенабор полезен для освоения.

Перед началом всего я настоятельно рекомендую удостовериться, что ваш mysql-сервер создаёт базы в умолчательной кодировке utf-8, и её же использует при коннекте от клиентов. Если нет, придётся добавить ключ к команде mysqladmin ниже. Также я не люблю писать «-u root» с каждым вызовом mysql, поэтому в секции [client] файла my.cnf у меня значится user=root.

Приступим же:
rails chat; cd chat


Теперь база:
mysqladmin create chat_development


В этом мега-проекте у нас будет целая одна таблица о двух стобцах: ник, и сообщение. Можно её создавать руками, но мы руками не любим, поэтому сделаем как положено, через миграцию рельсов. Это нам поможет в дальнейшем.
script/generate migration create_conversation

В db/migrate/001_create_conversation.rb после def self_up добавляем:



Рейлс забесплатно добавит нам колонки «id», «created_at» и «updated_at», и автоматически будет заботиться об их содержании. Запускаем миграцию, и таблица будет создана:
rake db:migrate


Для приличия надо что-то иногда выводить пользователю в броузер. Создадим общий шаблон app/views/layouts/chat.html.erb следующего вида:



Наиболее интересное место это предложение <%= yield -%>, собственно выводящее содержимое конкретного шаблона. Опишем их позже.

Теперь контроллер. Как и всё приложение, он крайне примитивен. Создадим
app/controllers/chat_controller.rb такого содержания:


Message.find выводит нам последние 30 сообщений (Select From), ориентруясь по «id». По хорошему надо бы по «created_at», но больно уж писать лень было.

Message.create сообщение добавляет (Insert Into), как легко понять.

В рамках этого развлечения систему управления пользователями мы себе позволить не можем, поэтому просто присваиваем посетителям цифровой ник. Если он им надоедает, они жмут «Новый ник», и мы им выдаём другой.

Нам нужны шаблоны. Шаблон это файл, который называется по умолчанию так же, как и акция контроллера. Иными словами, после отработки def say по умолчанию (а мы умолчания любим) будет вызван шаблон say.html.erb (в старом роре — say.rhtml). Создадим директорию шаблонов для нашего единственного контроллера chat.
mkdir app/views/chat


Центр этого проекта — шаблон вывода app/views/chat/index.html.erb:



Вот понаписано-то всякого! Разберём по кусочкам.

То, что :partial, это просто вставка фрагмента кода из другого файла, смотри ниже.

form_remote_tag создаст для нас обычную ХТМЛ-ную форму, но с обвесками в виде аяксовых вызовов из библиотек prototype и script.aculo.us, благодаря чему мы можем не выдавать обычный POST и не перерисовывать экран. Главный параметр вызова это :update, который указывает нам, элемент с каким id в нашей странице получит результат работы акции, указанной в :action. Контроллер по умолчанию тот же, «chat».

link_to_remote работает почти так же, мы используем его, чтобы заменить ник.

periodically_call_remote — это наш позор. Никогда не делайте так чаты. А делайте их с помощью плагина к монгрелу (или иному веб-серверу), который сможет обеспечивать server-push в случае появления новых сообщений. Но так как у нас всё очень примитивно, мы просто перезагружаем див с телом чата. Каждые 10 секунд (умолчание, да).

Фрагмент (partial) — это кусок шаблона, который можно использовать многократно, вроде вызова функции. Нам понадобится перерисовывать основное окно с содержимым чата в разных местах, поэтому создадим фрагмент app/views/chat/_conversation.html.erb:



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

В шаблоне index мы уже видели его вызов. Ещё он вызывается в шаблоне say. Создадим app/views/chat/say.html.erb:



При нажатии ввод после заполнения формы вызывается действие say. Найдите в коде контроллера def say.

И последнее. В последних версиях рора реализованы способы защиты от подмены содержимого форм в рамках сессии. По умолчанию они включены, но нам они будут мешать, так как мы можем выбросить сессию, а потом подать ТУ ЖЕ форму, за счёт использования аякса. Поэтому надо подправить app/controllers/application.rb. Найдите там строчку, начинающуюся на protect_from_forgery, и закомментируйте. Октоторпом в первой позици.

Проект готов. Запускаем сервер:
script/server


Посмотреть, что получилось: localhost:3000/chat.

Что же мы сделали? Код представляет из себя, как обычно в таких случаях, кровавое месиво из скриптового языка, ERB, ХТМЛ, CSS, эскуэля, и яваскрипта. Но благодаря усилиям разработчкиков рора, согласно общему мнению (с которым я вполне солидарен), архитектура и инструментарий рельсов даёт нам возможность сделать это месиво всё же менее кровавым, чем принято, и как можно большее количество кода записывать на наиболее эстетически предпочтительном языке, то есть на руби. SQL свёлся к огрызку «id DESC», а яваскрипт к прототайпному вызову $('sentence'), чтобы нам всегда возвращать фокус на окошко ввода. Прототайп (и рельсовая обёртка вокруг него) позволил нам обновлять фрагменты страницы в фоне, а скриптакулос зажигает поле ввода аццким жёлтым огнём после отправки реплики, а также создаёт эффект прилетания нового ника.

Весьма поучительно будет посмотреть на код страницы. Вы увидите, от какого количества выморочного кода на js нас избавили рельсы. Попробуйте сами. У вас должно получиться что-то похожее на то, что получилось у меня: chat.gde.to/chat. Успехов вам на рельсах.

Disclaimer: это не перевод и не адаптация. Весь текст оригинален, весь код создан специально для этой статьи.
Теги:
Хабы:
+2
Комментарии8

Публикации

Изменить настройки темы

Истории

Работа

Ruby on Rails
10 вакансий
Программист Ruby
8 вакансий

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн