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

Легковесные веб-приложения на Ruby

Время на прочтение5 мин
Количество просмотров8.6K

Быстрая разработка


Вдохновленный постами на западных блогах вроде «Clone TinyURL with 40 lines of Ruby» или «Clone Pastie in 15 Minutes with Sinatra & DataMapper» я решил попробовать пройти и заодно описать весь процесс реализации легковесного веб-приложения на руби, от проектирования до деплоймента.



Инструменты


Для руби есть огромное количество различных инструментов для быстрой разработки. Я остановился на следующих:

Sinatra — DSL для веба. Легковесный фреймворк, работающий по принципу «convention over configuration». Позволяет быстро и легко разрабатывать веб-приложения, и легко дополняется всем, что только может вам понадобиться. Основа нашего приложения.

DataMapper — ORM, главный конкурент ActiveRecord. В чем-то уступает, в чем-то превосходит вышеназванный, прекрасно работает с разными базами данных, легко конфигурируется и встраивается.

HAML — HTML для программистов. Язык разметки, чуть более красивый чем традиционный erb, генерирует чистый и валидный xhtml. Содержит в себе эквивалент для CSS — SASS.

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

Что будем писать?


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

Разбор кода


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

Для начала разберем структуру проекта, она очень проста:
comics.rb
config.ru
models.rb
public
views


Файл models.rb содержит в себе модели, конфигурацию базы данных и все что касается работы с ней. comics.rb содержит весь код для синатры. Так-же синатра по умолчанию подхватывает папки views, содержащую представления на haml и public с файлами доступными из веба (javascript, изображения).

Начнем с моделей.
models.rb
  1. DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3:///#{Dir.pwd}/comics.db")

Параметры БД на heroku содержатся в ENV['DATABASE_URL'], если такой переменной нет, то создаем sqlite-базу в каталоге с проектом. Править в исходниках ничего не придется.

models.rb
  1. class DateTime
  2. def rfc822
  3. self.strftime "%a, %d %b %Y %H:%M:%S %z"
  4. end
  5. end

Спецификация RSS 2.0 требует дату в формате RFC #822. Для этого добавим объектам класса DateTime метод rfc822, который отформатирует timestamp нужным образом, и именно его будем использовать в дальнейшем в представлениях.

comics.rb
  1. def protected!
  2. response['WWW-Authenticate'] = %(Basic) and \
  3. throw(:halt, [401, "Not authorized]) and \
  4. return unless authorized?
  5. end
  6. def authorized?
  7. comics = Comics.first
  8. @auth ||= Rack::Auth::Basic::Request.new(request.env)
  9. @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [comics.login, comics.password]
  10. end

Простая реализация аутентификации для Sinatra. Почти целиком взята из FAQ, отличие в том, что логин и пароль берутся из базы данных, вместо вшитых в исходник. Использовать предельно просто: достаточно в нуждающемся в аутентификации экшене вписать protected!

comics.rb
  1. get '/rss.xml' do
  2. content_type 'application/rss+xml', :charset => 'utf-8'
  3. @comics = Comics.first
  4. @strips = Strip.all :limit => 10
  5. haml(:rss, :layout => false)
  6. end

Отдача rss-фида. Меняем Content-Type, и добавляем: layout => false, чтобы фид не отрендерился в layout.

Теперь несколько хинтов в представлениях.
layout.haml
  1. %title= "#{@comics.title} — #{@strip.title}" rescue @comics.title

Если не использовать здесь механизм исключений, то при пустой переменной @strip нас остановит ошибка NoMethodError, так как у класса nil нет метода title. В руби такие штуки надо всегда держать в голове.

models.rb
  1. class Strip
  2. # объявляем property
  3. def next
  4. Strip.first(:created_at.gt => self.created_at, :order => [:created_at.asc])
  5. end
  6. def previous
  7. Strip.first(:created_at.lt => self.created_at)
  8. end
  9. def get_id
  10. self.id
  11. end
  12. default_scope(:default).update(:order => [:created_at.desc])
  13. end

layout.haml
  1. - tonext = "/#{@strip.next.get_id}" rescue "#"
  2. - toprevious = "/#{@strip.previous.get_id}" rescue "#"

Механизм понятен — поиск следующего и предыдущего стрипа для того, который смотрим сейчас, и вывод ссылок на них в представлении. Почему надо было делать отдельный метод get_id, вместо того чтобы напрямую использовать существующий id? Дело в том, что если мы смотрим последний на текущий момент стрип, то метод next вернет nil. А у nil в свою очередь есть метод id, который не долго думаю вернет «4». Можете убедиться в этом сами, поэкспериментировав в irb.

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

Деплоймент


Написанное приложение легко запустится как и любое другое приложение на синатре командой ruby comics.rb. Но мы ведь хотим показать его миру, и в этом нам поможет Heroku. Регистрируемся на heroku, и устанавливаем себе на локальную машину gem heroku. Теперь пишем конфиг для Rack:
config.ru
  1. require 'comics'
  2. run Sinatra::Application

Следующим шагом создаем приложение на heroku, и пушим туда код. Условимся, что приложение уже лежит у вас в git-репозитории:
heroku create comics
git push heroku master

Осталось только забить базу данных начальными данными, для этого в models.rb есть метод install:
heroku console
install

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

Ссылки


Comics на GitHub
Демо на Heroku (Админка, пароль по запросу в хабрапочту).
Теги:
Хабы:
Всего голосов 49: ↑47 и ↓2+45
Комментарии24

Публикации