Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Ruby on Rails

Загрузка файлов с Rails и Carrierwave

by
Length:MediumLanguages:

Russian (Pусский) translation by Marat Amerov (you can also view the original English article)

Это очередная статья из серии «Загрузка с Rails». Сегодня мы познакомимся с Carrierwave - одним из самых популярных решений для загрузки файлов с Rails. Мне нравится Carrierwave, потому с ним легко начать работу, у него множество функций из коробки, и для него представлены десятки "how to"  статей, написанные сообществом.

Из этой статьи вы узнаете, как:

  • Интегрировать Carrierwave в Rails приложение
  • Добавить валидацию
  • Сохранять файлы через запросы
  • Удалять файлы
  • Генерировать миниатюрные эскизы
  • Загружать файлы из удаленных хостов
  • Загружать несколько файлов за раз
  • Добавить поддержку для облачного хранилища

Исходный код этой статьи доступен на GitHub.

Создание фундамента приложения

Как всегда, начнем с создания нового Rails приложения:

Для этой демонстрации я буду использовать Rails 5.0.2. Обратите внимание, что Carrierwave версии 1 поддерживает только Rails 4+ и Ruby 2. Если вы все еще используете Rails 3, подключите Carrierwave версии 0.11.

Чтобы увидеть Carrierwave в действии, мы  создадим очень простое приложение для ведения блога с единственной моделью Post. Она будет иметь следующие основные атрибуты:

  • title (string)
  • body (text)
  • image (string) - это поле будет содержать изображение (имя файла, если быть точным), прикрепленное к посту

Создадим и применим новую миграцию:

Установим несколько маршрутов:

config/routes.rb

Также создадим очень простой контроллер:

posts_controller.rb

Теперь, давайте создадим представление для index:

views/posts/index.html.erb

Также соответствующий partial:

views/posts/_post.html.erb

Здесь я использую метод Rails truncatе для отображения только первых 150 символов из поста. Прежде чем мы создадим другие представления и partial формы, давайте сначала интегрируем Carrierwave в приложение.

Интеграция Carrierwave

Добавим новый гем в Gemfile:

Gemfile

Запуск:

Carrierwave хранит свою конфигурацию внутри загрузчиков, включенных в модели. Чтобы создать загрузчик, используйте следующую команду:

Теперь, внутри app/uploaders, вы обнаружите новый файл с именем image_uploader.rb. Обратите внимание, что у него есть несколько полезных комментариев и примеров, соответственно вы можете использовать его для начала работы. В этой демонстрации мы будем использовать ActiveRecord, но Carrierwave также поддерживает Mongoid, Sequel и DataMapper.

Затем нам нужно включить или монтировать этот загрузчик в модель:

models/post.rb

У загрузчика уже есть оптимальные настройки по умолчанию, но, по крайней мере, нам нужно выбрать, куда будут загружены файлы. На данный момент давайте использовать файловую систему:

uploaders/image_uploader.rb

По умолчанию файлы будут загружены в каталог public/uploads, поэтому лучше исключить его из системы контроля версий:

.gitignore

Вы также можете изменить метод store_dir внутри вашего загрузчика, чтобы выбрать другое местоположение.

На этом этапе мы можем создать новое представление и partial формы, чтобы начать загрузку файлов:

views/posts/new.html.erb

views/posts/_form.html.erb

Обратите внимание, что PostsController не нужно модифицировать, поскольку мы уже разрешили атрибут image.

Наконец, создадим представление для редактирования:

views/posts/edit.html.erb

Вот оно! Вы можете запустить сервер и попытаться создать пост с изображением. Проблема в том, что это изображение нигде не показывается, поэтому перейдем к следующему разделу и добавим страницу показа!

Показ изображений

Итак, единственное, что мы еще не создали, это - представление show. Добавим его сейчас:

views/posts/show.html.erb

Как вы можете видеть, отображение вложения очень простая задача: все, что вам нужно сделать, это - вызвать @post.image.url, чтобы получить URL-адрес изображения. Чтобы получить путь к файлу, используйте метод current_path. Обратите внимание, что Carrierwave также предоставляет метод image?  для проверки того, присутствует ли вообще вложение (сам метод image никогда не вернет nil, даже если файл отсутствует).

Теперь, после перехода к посту, вы должны увидеть изображение, но оно может показаться слишком большим: в конце концов, мы нигде не ограничиваем размеры. Конечно, мы могли бы уменьшить масштаб изображения с помощью некоторых правил CSS, но гораздо лучше создать миниатюру после загрузки файла. Однако это требует некоторых дополнительных шагов.

Генерация эскизов

Чтобы обрезать и масштабировать изображения, нам нужен отдельный инструмент. Из коробки Carrierwave имеет поддержку гемов RMagick и MiniMagick, которые, в свою очередь, используются для управления изображениями с помощью ImageMagick. ImageMagick - это решение с открытым исходным кодом, позволяющее редактировать существующие изображения и создавать новые, поэтому перед продолжением необходимо загрузить и установить его. Затем вы можете выбрать любой из двух гемов. Я буду придерживаться MiniMagick, потому что его гораздо проще установить, и он имеет лучшую поддержку:

Gemfile

Запуск:

Затем включим MiniMagick в загрузчик:

uploaders/image_uploader.rb

Теперь нам просто нужно ввести новую версию для нашего загрузчика. Концепция версий (или стилей) используется во многих библиотеках для загрузки файлов; Это означает, что будут созданы дополнительные файлы на основе исходного вложения, например, с различными размерами или форматами. Добавим новую версию под названием thumb:

uploaders/image_uploader.rb

У вас может быть столько версий, сколько вам нужно, и, более того, версии могут быть построены поверх других:

uploaders/image_uploader.rb

Если вы уже загрузили некоторые изображения, у них нет доступных эскизов. Это не проблема, поскольку вы можете воссоздать их с консоли Rails:

Наконец, отобразим эскиз со ссылкой на исходное изображение:

views/posts/show.html.erb

Запустим сервер и посмотрим на результат!

Добавление валидации

В настоящее время наш загрузчик работает, но мы не валидируем пользовательский ввод, что конечно, плохо. Пока мы хотим работать только с изображениями, давайте добавим в белый список расширения .png, .jpg и .gif:

uploaders/image_uploader.rb

Вы также можете добавлять проверки типа контента, определяя метод content_type_whitelist:

uploaders/image_uploader.rb

Кроме того, можно занести некоторые типы файлов в черный список, например исполняемые файлы, путем определения метода content_type_blacklist.

Помимо проверки типа файла и расширения, давайте добавим к нему ограничение в размене - меньше 1 мегабайта. Для этого нам понадобится дополнительный гем, поддерживающий проверку файлов для ActiveModel:

Gemfile

Установка:

Теперь добавим желаемые проверки (обратите внимание, что я также добавляю проверки атрибутов title и body):

models/post.rb

Следующее, что нужно сделать, это добавить переводы I18n для сообщений об ошибках Carrierwave:

config/locales/en.yml

В настоящее время мы не показываем ошибки валидации , поэтому давайте создадим общий partial:

views/shared/_errors.html.erb

Используйте этот partial внутри формы:

views/posts/_form.html.erb

Теперь попробуем загрузить недопустимые файлы и понаблюдаем результат. Это должно работать, но если выбрать валидный файл и не заполнить заголовок или тело, тогда проверки все равно будут происходить, и будет отображаться ошибка. Однако поле файла будет очищено, и пользователю нужно будет снова выбрать изображение, что не очень удобно. Чтобы исправить это, нам нужно добавить другое поле в форму.

Сохранение файлов между запросами

Сохранение файлов из redisplays на самом деле довольно просто. Все, что вам нужно сделать, это добавить новое скрытое поле и разрешить его внутри контроллера:

views/shared/_form.html.erb

posts_controller.rb

Теперь image_cache будет заполнен автоматически, и изображение не будет потеряно. Может оказаться полезным также отобразить эскиз, чтобы пользователь понял, что изображение успешно обработано:

views/shared/_form.html.erb

Удаление изображений

Еще одна очень распространенная функциональность - возможность удаления прикрепленных файлов при редактировании записи. С Carrierwave реализация этой функциональности не является проблемой. Нужно просто добавить новый флажок в форму:

views/shared/_form.html.erb

Разрешим атрибут remove_image:

posts_controller.rb

Вот оно! Чтобы удалить изображение вручную, используйте метод remove_image!:

Удаленная Загрузка

Carrierwave также предоставляет очень классную функцию из коробки: возможность загружать файлы из удаленно по их URL-адресу. Давайте добавим эту возможность, добавив новое поле и получив соответствующий атрибут:

views/shared/_form.html.erb

posts_controller.rb

Круто? Вам вообще не нужно вносить какие-либо изменения, Вы можете сразу проверить эту возможность!

Множественная загрузка

Предположим, мы хотим, чтобы в нашем посте было доступно несколько вложений. С текущей настройкой это невозможно, но, к счастью, Carrierwave поддерживает такой сценарий. Чтобы реализовать эту функционал, необходимо добавить либо сериализованное поле (для SQLite), либо поле JSON (для Postgres или MySQL). Я предпочитаю последний вариант, поэтому давайте перейдем к новому адаптеру базы данных. Удалите гем sqlite3 из Gemfile и добавьте вместо него pg:

Gemfile

Установка:

Изменение конфигурации базы данных:

config/database.yml

Создайте соответствующую базу данных Postgres, а затем создайте и примените миграцию:

Если вы предпочитаете придерживаться SQLite, следуйте инструкциям, приведенным в документации Carrierwave.

Теперь подключите загрузчики (обратите внимание на множественную форму!):

model/post.rb

Я использую один и тот же загрузчик для вложений, но, конечно, вы можете создать новый с другой конфигурацией.

Добавьте несколько полей для файлов в форму:

views/shared/_form.html.erb

Пока поле для attachments будет содержать массив, оно должно быть разрешено следующим образом:

posts_controller.rb

Наконец, Вы можете перебирать вложения и показывать их как обычно:

views/shared/show.html.erb

Обратите внимание, что каждое вложение будет иметь эскиз, настроенный в нашем ImageUploader.

Использование облачного хранилища

Использование файлового хранилища не всегда удобно и / или не возможно, так как, например, на Heroku нет возможности хранить пользовательские файлы. Следовательно, Вы можете спросить, как подружить Carrierwave с облачным хранилищем Amazon S3? Ну, это тоже довольно простая задача. Carrierwave зависит от fog-aws для реализации этого функционала:

Gemfile

Установка:

Давайте создадим инициализатор для Carrierwave и настроим облачное хранилище:

config/initializers/carrierwave.rb

Существуют и другие доступные опции, которые можно найти в документации.

Я использую dotenv-rails для безопасного хранения переменных окружения, но Вы можете выбрать любой другой вариант. Однако убедитесь, что ваша пара ключей S3 недоступна публично, потому что в противном случае любой может загрузить что-нибудь в ваш бакет!

Затем замените строку storage: file:

uploaders/image_uploader.rb

Помимо S3, Carrierwave поддерживает загрузку в Google Storage и Rackspace. Эти сервисы также легко настраиваются.

Заключение

На сегодня, это все. Мы рассмотрели все основные функции Carrierwave, и теперь Вы можете начать использовать его в своих проектах. Он имеет несколько дополнительных опций, поэтому просмотрите документацию.

Если вы застряли, не стесняйтесь оставлять свои вопросы. Кроме того, может быть полезно заглянуть в wiki- Carrierwave, в котором содержатся полезные «how to» статьи и ответы на многие распространенные вопросы.

Благодарю вас за то, что вы остались со мной, и счастливо  покодить!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.