В первой части статьи мы написали REST приложение и на 1/3 настроили Redactor.js. Сегодня мы закончим наше изобретение, написав интерфейс управления загруженными изображениями, и обеспечим загрузку файлов. При загрузке файлов мы не будем использовать CarrierWave, а пойдем обычным путем Ruby.
Начнем с загрузки файлов. Предполагаю, что сейчас у вас такой файл init.rb:
# coding: utf-8
require 'rubygems'
require 'sinatra'
require 'data_mapper'
require 'carrierwave'
require 'carrierwave/datamapper'
require 'rmagick'
require 'json'
set :public_directory, './public'
class ImageUploader < CarrierWave::Uploader::Base
def store_dir
'uploads/images'
end
def extension_white_list
%w(jpg jpeg gif png bmp)
end
include CarrierWave::RMagick
version :thumb do
process :resize_to_fill => [100,74]
end
storage :file
end
class Post
include DataMapper::Resource
property :id, Serial
property :title, String
property :body, Text
end
class UploadedImages
include DataMapper::Resource
property :id, Serial
property :image, String
property :thumb, String
mount_uploader :file, ImageUploader
end
class UploadedFiles
include DataMapper::Resource
property :id, Serial
property :name, String
property :path, String
end
DataMapper.setup(:default, ENV['DATABASE_URL'] || 'sqlite:./db/base.db')
DataMapper.finalize
DataMapper.auto_upgrade!
get '/' do
'REST приложение на Sinatra <a href="/posts">Перейти к страницам</a>'
end
#List posts
get '/posts' do
<hh user=posts> = Post.all
erb :'index'
end
#Create new Post
get '/posts/new' do
erb :'posts/new'
end
post '/posts/new' do
params.delete 'submit'
<hh user=post> = Post.create(params)
redirect '/posts'
end
#Edit post
get '/posts/:id/edit' do
<hh user=post> = Post.get(params[:id])
erb :'posts/edit'
end
#Update post
put '/posts/:id/edit' do
post = Post.get(params[:id])
post.title = (params[:title])
post.body = (params[:body])
post.save
redirect '/posts'
end
#Delete post
get '/posts/:id/delete' do
Post.get(params[:id]).destroy
redirect '/posts'
end
post '/upload/image' do
params[:file]
filename = params[:file][:filename]
file = params[:file][:tempfile]
upload = UploadedImages.new
upload.file = params[:file]
upload.image = params[:image] = '/uploads/images/' + File.join(filename)
upload.thumb = params[:thumb] = '/uploads/images/thumb_' + File.join(filename)
upload.save
<hh user=images> = UploadedImages.all
File.open("public/uploads/images/imageslist.json","w") do |f|
f.write JSON.pretty_generate(<hh user=images>)
end
'<img src="/uploads/images/' + File.join(filename) + '" />'
end
Итак, создадим папку files в директории public/uploads, напишем новую модель UploadedFiles и добавим метод post для загрузки файлов
set :files, File.join(settings.public_directory, 'uploads/files') #берем из настройки public директории (set :public_directory, './public' почти в самом начале init.rb) ее путь и прибавляем путь, куда будут загружаться файлы
class UploadedFiles
include DataMapper::Resource
property :id, Serial #идентификатор
property :name, String #имя загруженного файла
property :path, String #путь к загруженному файлу
end
post '/upload/file' do
params[:file]
filename = params[:file][:filename]
file = params[:file][:tempfile]
ext = File.extname(filename) #устанавливаем переменную для проверки расширения файла, нам же не нужно, чтобы пытались загружать что угодно.
if ext == ".doc" || ext == ".zip" || ext == ".dmg" #здесь я установил 3 допустимых расширения файла doc, zip, dmg, при желании список разрешенных файлов всегда можно увеличить.
File.open(File.join(settings.files, filename), 'wb') {|f| f.write file.read } #загрузили - сохранили
upload_f = UploadedFiles.new #создаем новый UploadedFile в базе данных
upload_f.name = params[:name] = File.join(filename) #в моделе UploadedFiles поле :name, записываем туда имя загруженного файла
upload_f.path = params[:path] = '/uploads/files/' + File.join(filename) #в моделе UploadedFiles поле :path, записываем туда путь к загруженному файлу
upload_f.save #сохраняем
'<a href="/uploads/files/' + File.join(filename) + '" />' + File.join(filename) + '</a>' #вставляем в редактор ссылку на файл
end
end
Теперь осталось сказать редактору как именно загружать файлы, откроем layout.erb найдем строку
$('.redactor_1').redactor({toolbar: 'default', lang: 'ru', imageUpload: '/upload/image', imageGetJson: '/uploads/images/imageslist.json'});
Добавим настройку fileUpload: '/upload/file' чтобы выглядело следующим образом
$('.redactor_1').redactor({toolbar: 'default', lang: 'ru', imageUpload: '/upload/image', fileUpload: '/upload/file', imageGetJson: '/uploads/images/imageslist.json'});
Все необходимые настройки мы сделали: создали модель, настроили путь к загружаемым файлам, собственно реализовали саму загрузку файла, сделали проверку на разрешенные файлы. Вот что хотелось бы отметить, неплохо было бы реализовать сообщение об ошибке, если расширение файл не соответствует разрешенному, но тут есть 2 НО: во-первых, Redactor.js все делает во фрейме и, если сделать сообщение об ошибке, то оно будет писаться в textarea, что, на мой взгляд, не является хорошей идеей, если попытаться реализовать сообщение об ошибке через gem sinatra-flash, то опять не вариант, так как ошибка появится только после перегрузки страницы. Ну может более опытные люди подскажут в какую сторону копать.
Теперь приступим к управлению загруженными изображениями, максимум что мы сделаем, это список всех загруженных изображений и их удаление.
Добавим в init.rb
#init.rb
#List UploadedImages
get '/images' do
@ uploadedimage = UploadedImages.all #задаем переменную для вывода всех загруженных изображений по адресу /images (убрать пробел между собакой и uploadedimage)
erb :'images' #рендерим images.erb
end
#Delete UploadedImage
get '/images/:id/delete' do #обращаемся к изображению через его ID
UploadedImages.get(params[:id]).destroy #удаляем (честно говоря, для меня какое-то волшебство, удаляет строки в бд и файлы!...)
redirect '/images' #редеректимся на страницу со всеми оставшимися изображениями
end
Создадим в директории views файл images.erb
<strong><a href="/posts">Перейти ко всем post'ам</a></strong>
<h2>Список загруженных файлов</h2>
<% @ uploadedimage.each do |uploadedimages| %>
<a href="<%= uploadedimages.image %>"><img src="<%= uploadedimages.thumb %>"></a>
#ссылка на полное изображение при клике на его превью
<a href="/images/<%= uploadedimages.id %>/delete">удалить</a>
<% end %>
Ну вот мы и закончили наше приложение. По аналогии с управлением изображений можно сделать и управление файлами. Думаю получилось неплохо. И это еще не конец, я продолжаю изучать Ruby и Sinatra и будут еще статьи.
P.S.: Везде где попадается
<hh user=posts>
или
<hh user=images>
просто замените на @название_переменной
Автор: aylo