вівторок, 22 травня 2012 р.

CarrierWave з DataMapper у Sinatra

У вільний час займаюся розробкою веб-додатку на Sinatra з використанням DataMapper. І ось задався питанням завантаження аватарів на сервер та їх після-обробкою.

Переглянувши доступні інструменти для забезпечення цієї функціональності, вибір впав на бібліотеку CarrierWave, яка на відміну від більшості інших не зав'язана на Rails/ActiveRecord.

CarrierWave описує себе, як "першокласне рішення для завантаження файлів для Rails, Sinatra та інших веб-додатків на основі Rack". Проект був започаткований у серпні 2008 року, і перший випуск відбувся в березні 2009 року. Перша його назва була Merb::Upload і він був без підтримки Rails.

Той факт, що CarrierWave почав своє життя в якості плагіна для Merb може пояснити його модульність, гнучкість і розширюваність.

Завдяки fog, він має підтримку Amazon S3, Rackspace Cloud Files і Google Storage for Developers. Він також підтримує звичайне зберігання файлів і GridFS в MongoDB.
Має підтримку незліченної кількості ORM: ActiveRecord, Mongoid, DataMapper, Sequel, MongoMapper, CouchDB.
Обробка зображення доступна засобами RMagick, ImageScience або MiniMagick.
Сама по собі ця бібліотека дуже добре документована, і якщо раптом когось цікавлять деталі, то читайте wiki.

У цій статті для прикладу ми напишемо просту фотогалерею.
Наступні gem`и повинні бути встановлені:
  • sinatra
  • datamapper
  • dm-sqlite-adapter
  • slim
  • carrierwave - для завантаження зображень
  • carrierwave-datamapper - для зв'язку DataMapper і CarrierWave
  • rmagick - для створення мініатюр зображень(в Ubuntu потрібно встановити пакет libmagick++-dev)


Налаштування підключення до бази даних і створення таблиці для зберігання інформації про зображення у галереї.
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/photogallery.sqlite3")

class Image
  include DataMapper::Resource

  property :id, Serial
  property :title, Text
end

DataMapper.auto_upgrade!

Налаштування CarrierWave. Для того щоб він правильно працював потрібно також встановити gem carrierwave-datamapper і rmagick.

Клас завантажувача успадкований від CarrierWave::Uploader::Base:
class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  storage :file

  process :resize_to_fit => [800, 800]

  version :thumb do
    process :resize_to_fill => [200, 200]
  end

  def store_dir
    'uploads'
  end

  def extension_white_list
    %w(bmp gif jpg jpeg png)
  end
end
Для того, щоб змінити розташування завантажених файлів необхідно просто перевизначити метод store_dir. А також створити каталог 'public/uploads'.

Метод extension_white_list визначає, які розширення файлів дозволені для завантаження.

При завантаженні зображення буде масштабуватися не більше ніж 800 на 800 пікселів. А його мініатюрна версія :thumb буде масштабована і обрізана рівно 200 на 200 пікселів.

Завантажувач може бути використаний наступним чином:
uploader = ImageUploader.new
uploader.store!(my_file)                              # розмір: 1024x768

uploader.url # => '/url/to/my_file.png'               # розмір: 800x600
uploader.thumb.url # => '/url/to/thumb_my_file.png'   # розмір: 200x200

З'єднання моделі DataMapper із завантажувачем CarrierWave за допомогою методу mount_uploader:
class Image
  include DataMapper::Resource

  property :id, Serial
  property :title, Text

  mount_uploader :image, ImageUploader
end

Маршрути:
get '/' do
  @images = Image.all

  slim :index
end

post '/' do
  image = Image.new(:title => params[:title])
  image.image = params[:image]
  image.save

  redirect '/'
end

Шаблон Slim. Мініатюри усіх завантажених зображень і форма для додавання нових:
__END__

@@ index
- @images.each do |i|
  p
    = i.title
  a href="#{i.image.url}"
    img src="#{i.image.thumb.url}"

form action='/' method='post' enctype='multipart/form-data'
  fieldset
    p
      label for='title' Title:
      input name='title' type='text'
    p
      label for='image' Image:
      input name='image' type='file'
    p
      input type='submit' value='Save'


Весь код можна подивитись на GitHub.

Немає коментарів: