Реализация полнофункциональной загрузки медиа в веб-приложении
Предположим, у нас есть веб-приложение, которое обрабатывает создание, чтение, обновление и удаление статей, и каждая статья должна иметь галерею изображений. Я должен сделать однозначное отношение между статьей и галереей и однозначное отношение между галереей и медиа.
HTML5 предоставляет множество функций, таких как мультизагрузка, поэтому я хочу использовать для этого превосходный http://blueimp.github.io/jQuery-File-Upload/ плагин. Проблема в том, как обработать загрузку файла "в память", как данные другой формы?
Например, когда мы показываем страницу для создания новой статьи, мы должны иметь возможность заполнить поля данных статьи и выбрать изображения для загрузки, затем, когда мы нажимаем кнопку "Сохранить", изображения должны начать загрузку, а затем форма должна быть отправлена. Если проверка не пройдена, изображения должны по-прежнему отображаться на веб-интерфейсе, но на стороне сервера должна сохраняться ссылка.
Одним из решений является создание чего-то вроде "создания временного идентификатора сеанса объекта" перед отображением всей формы, и этот идентификатор можно использовать для создания временного каталога для сохранения загрузок, поэтому после успешного сохранения формы эти изображения могут быть перемещены в соответствующий каталог, но как сделать "создать временный идентификатор сеанса создания сущности"?
Другим решением, которое я считаю, является подход "с идентификатором редактирования", потому что мы можем обрабатывать загрузки с ранее сохраненным идентификатором галереи, но иногда я не могу сохранить новую пустую статью с галереей, потому что некоторые поля не должны быть пустыми в дБ
Для Rails я увидел https://github.com/thoughtbot/paperclip gem, который в Readme говорит:
Скрепка предназначена как простая библиотека вложений файлов для Active Record. Цель этого состояла в том, чтобы максимально упростить настройку и обрабатывать файлы так же, как и другие атрибуты. Это означает, что они не сохраняются в свои конечные местоположения на диске и не удаляются, если задано значение nil, до тех пор, пока не будет вызван ActiveRecord::Base#save.
У меня вопрос как это работает?
2 ответа
Проблема с включением загрузки файлов в маске создания заключается в том, что в конечном итоге вы получите потерянные файлы. Это связано с тем, что пользователь может инициировать загрузку без сохранения фактического объекта. При создании собственного UploadBundle я некоторое время думал об этой проблеме и пришел к выводу, что действительно правильного решения не существует.
В итоге я реализовал это так:
Учитывая тот факт, что наша проблема возникает из-за потерянных файлов, я создал Orphanage
который отвечает за управление этими файлами. Загруженные файлы сначала будут храниться в отдельном каталоге вместе с session_id. Это помогает различать файлы разных пользователей. После отправки формы для создания фактической сущности вы можете получить файлы из детского дома, используя только свой идентификатор сеанса. Если форма была действительной, вы можете переместить файлы из каталога временного приюта в конечный пункт назначения ваших файлов.
Этот метод имеет несколько подводных камней:
- Сам каталог приюта должен регулярно очищаться с помощью задания cron или чего-либо подобного.
- Если пользователь загрузит файлы и решит не отправлять форму, а вместо этого начать заново с новой формы, вновь загруженные файлы будут перемещены в тот же каталог. Поэтому вы получите загруженные файлы как в первый раз, так и во второй раз после получения загруженных файлов.
Это не окончательное решение этой проблемы, а скорее обходной путь. Однако, на мой взгляд, он чище, чем использование временных сущностей или систем хранения на основе сеансов.
Упомянутый пакет доступен на Github и поддерживает как Orphanage
и jQuery File Uploader
плагин.
Лично я не работал с делом, но у моей коллеги была похожая головоломка. Она использовала
punkave / Symfony2-файл-загрузчик-расслоение
Это пакет, который оборачивает плагин jQuery File Upload. Это на ранних стадиях, и многие вещи отсутствуют, например, событие, но мы дали ему шанс.
Вот что мы делаем: в newAction() мы создаем сущность, генерируем уникальный идентификатор dir и сохраняем идентификатор в сущности (через обычную setDirId()). Затем мы создаем форму, которая содержит скрытое поле dirId.
Мы загружаем файлы в temp dir на сервер через ajax, а не во время отправки. Для запроса Ajax требуется идентификатор. Хранит файлы в temp_dir/prefix_ID
Чем это довольно просто. Форма отправлена. Если форма верна - переместите файлы из temp в dest dir. Если нет - у нас есть идентификатор, и мы можем показать изображения.
Однако мы не храним информацию об отдельных файлах в отдельной таблице в базе данных. Каждый раз, когда мы читаем содержимое папки, которая соответствует нашему dirId.
Я знаю, что это не то решение, о котором ты просишь. Это скорее обходной путь.