lest, just lest

Заметки о web-разработке, администрировании Linux и настройке Mac OS X

Sinatra и DataMapper: пример сервиса сокращения ссылок

без комментариев

В мире Ruby существует несколько ORM библиотек. Самая популярная библиотека ActiveRecord является и самой тяжелой, к тому же ее не особо удобно использовать вне Rails. Для небольших приложений на фреймворке Sinatra наиболее оптимальным вариантом является библиотека DataMapper, которая не уступает по функциональности, а в некоторых моментах опережает своего главного конкурента.

На примере простого сервиса сокращения ссылок рассмотрим работу с DataMapper внутри Sinatra.

Устанавливаем гемы с DataMapper и адаптером Sqlite к нему:

gem install data_mapper do_sqlite3

DataMapper состоит из нескольких библиотек, использовать будем только некоторые из них:

  • dm-core - ядро DataMapper'а.
  • dm-validations - готовые методы для проверки входных данных.
  • dm-timestamps - автоматическое создание и обновление полей created_at, updated_at.

В app.rb подключим необходимые библиотеки из DataMapper и настроим соединение с базой данных:

require 'dm-core'
require 'dm-validations'
require 'dm-timestamps'

DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/#{Sinatra::Application.environment}.sqlite")

Настала пора написать класс модели данных:

class Link
  include DataMapper::Resource

  property :id, Serial
  property :url, String, :length => 255, :required => true, :index => true
  timestamps :at

  validates_format :url, :as => :url
end

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

Метод timestamps (доступен при подключении dm-timestamps) создает поля created_at и updated_at и обновляет их при добавлении/изменении записи в базе данных.

Также используется метод validates_format из библиотеки dm-validations для того, чтобы перед сохранением происходила проверка на корректность поля url.

Изменение структуры базы данных делаем с помощью rake, для этого создаем Rakefile:

require 'app'

desc 'Migrate DataMapper database'
task :migrate do
  DataMapper.auto_migrate!
end

Метод auto_migrate! создает таблицы, которых еще нет, и при необходимости добавляет новые поля в уже существующие.

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

rake migrate

В коротких ссылках будем использовать поле id, закодированное с помощью библиотеки base62.

Устанавливаем соответствующий gem:

gem install base62

Подключаем библиотеку base62 в app.rb:

require 'base62'

Для удобного экранирования при выводе добавим в хелперах алиас к методу escape_html из Rack::Utils, а для генерации ссылки напишем хелпер link_url, использующих метод base62_encode из библиотеки base62:

helpers do
  include Rack::Utils

  alias :h :escape_html

  def link_url(link)
    "http://#{request.host}/#{link.id.base62_encode}"
  end
end

Для запроса GET на главную страницу создаем новый объект модели Link и рендерим шаблон index.haml:

get '/' do
  @link = Link.new
  haml :index
end

При POST запросе получаем из базы данных существующую ссылку по url или создаем и сохраняем новую с помощью метода first_or_create:

post '/' do
  @link = Link.first_or_create(:url => params[:url])
  haml :index
end

В шаблоне index.haml выводим форму добавления ссылки с ошибкой в случае неправильного url:

%form{:action => '/', :method => :post}
  %input{:type => :text, :size => 40, :name => :url, :value => @link.url || 'http://'}
  %input{:type => :submit, :value => 'Shorten'}
  - if @link.errors[:url].any?
    .error=h 'may be some error in your url?'

Выводим информацию о созданной короткой ссылке, с помощью метода saved? проверяется, что ссылка уже сохранена в базе данных (то есть произошел сабмит формы и ошибок не было):

- if @link.saved?
  %dl
    %dt Original:
    %dd=h @link.url
    %dt Shorted:
    %dd
      %a{:href => link_url(@link)}=h link_url(@link)

Для перенаправления по коротким ссылкам используем роутинг с регулярным выражением:

get %r{/(\w+)} do
  @link = Link.get(params[:captures].first.base62_decode)
  throw :halt, [404, "Not found"] unless @link
  redirect @link.url
end

В массиве params[:captures].first будет содержаться буквы и цифры после / в короткой ссылке, являющиеся закодированным id. Преобразование base62 строки в число делаем с помощью метода base62_decode, а метод get модели позволяет получить запись по первичному ключу (то есть полю id).

Полный исходный код можно взять на github:

git clone git://github.com/lest/url-shortener.git

Увидеть приложение в работе можно по ссылке http://tourl.heroku.com/.

Related posts:

  1. Hello world с помощью Ruby, Sinatra и Haml
  2. Использование Sinatra внутри Rails Metal
  3. Запуск web-приложения на Sinatra с Phusion Passenger
  4. CKEditor в Ruby on Rails c загрузкой файлов через SWFUpload
  5. Emacs RSpec mode

Автор: lest

Февраль 24, 2010 в 12:26

Опубликовано в ruby

Метки: , , , ,

Leave a Reply