В первой части статьи мы написали REST приложение и на 1/3 настроили Redactor.js. Сегодня мы закончим наше изобретение, написав интерфейс управления загруженными изображениями, и обеспечим загрузку файлов. При загрузке файлов мы не будем использовать CarrierWave, а пойдем обычным путем Ruby.
Начнем с загрузки файлов. Предполагаю, что сейчас у вас такой файл init.rb:
Итак, создадим папку files в директории public/uploads, напишем новую модель UploadedFiles и добавим метод post для загрузки файлов
Теперь осталось сказать редактору как именно загружать файлы, откроем layout.erb найдем строку
Добавим настройку fileUpload: '/upload/file' чтобы выглядело следующим образом
Все необходимые настройки мы сделали: создали модель, настроили путь к загружаемым файлам, собствен��о реализовали саму загрузку файла, сделали проверку на разрешенные файлы. Вот что хотелось бы отметить, неплохо было бы реализовать сообщение об ошибке, если расширение файл не соответствует разрешенному, но тут есть 2 НО: во-первых, Redactor.js все делает во фрейме и, если сделать сообщение об ошибке, то оно будет писаться в textarea, что, на мой взгляд, не является хорошей идеей, если попытаться реализовать сообщение об ошибке через gem sinatra-flash, то опять не вариант, так как ошибка появится только после перегрузки страницы. Ну может более опытные люди подскажут в какую сторону копать.
Теперь приступим к управлению загруженными изображениями, максимум что мы сделаем, это список всех загруженных изображений и их удаление.
Добавим в init.rb
Создадим в директории views файл images.erb
Ну вот мы и закончили наше приложение. По аналогии с управлением изображений можно сделать и управление файлами. Думаю получилось неплохо. И это еще не конец, я продолжаю изучать Ruby и Sinatra и будут еще статьи.
Исходный код на github
P.S.: Везде где попадается
Начнем с загрузки файлов. Предполагаю, что сейчас у вас такой файл 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
@posts = Post.all
erb :'index'
end
#Create new Post
get '/posts/new' do
erb :'posts/new'
end
post '/posts/new' do
params.delete 'submit'
@post = Post.create(params)
redirect '/posts'
end
#Edit post
get '/posts/:id/edit' do
@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
@images = UploadedImages.all
File.open("public/uploads/images/imageslist.json","w") do |f|
f.write JSON.pretty_generate(@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') #загрузили - сохранили
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><br> #ссылка на полное изображение при клике на его превью
<a href="/images/<%= uploadedimages.id %>/delete">удалить</a><br><br>
<% end %>
Ну вот мы и закончили наше приложение. По аналогии с управлением изображений можно сделать и управление файлами. Думаю получилось неплохо. И это еще не конец, я продолжаю изучать Ruby и Sinatra и будут еще статьи.
Исходный код на github
P.S.: Везде где попадается
<hh user=posts>
или <hh user=images>
просто замените на @название_переменной