Upload file với gem Dragonfly
Bài đăng này đã không được cập nhật trong 3 năm
Xin chào các bạn (lay2)
Trong một Web Application, upload file là một chức năng gần như không thể thiếu.
Ví dụ như upload ảnh làm avatar, share video, music, hay upload các file csv, excel để xử lý,... nói chung là không thể thiếu được (yaoming)
Trong Ruby on Rails, khi nhắc đến Upload, người ta nghĩ tới ngay tới các gem như Carrierwave
hay Paperclip
bởi sự thông dụng của nó.
Hôm nay, tôi sẽ giới thiệu tới các bạn một gem khác tên là Dragonfly
.
Ưu điểm:
- Cực kỳ dễ sử dụng (ít nhất là với
Carrierwave
vàPaperclip
kappa) - Tích hợp ngon lành với ImageMagick - Là thư viện để xử lý ảnh mạnh mẽ (các bạn có thể đọc thêm ở đây)
- Tự động lưu trữ thông tin về file upload.
- Hoạt động tốt với file upload có dung lượng lớn.
- Các validation và callback rất chi tiết.
- ...
Trong bài viết dưới đây, tôi sẽ hướng dẫn các bạn sử dụng con "chuồn chuồn" này để upload ảnh lên local và Amazon S3. (len)
I. Demo
Các công việc phải làm:
- Tạo web app mới, add các gem cần thiết.
- Config và generate file.
- Tạo layout cơ bản.
- Xử lý ở Controller và Model để upload file lên local.
- Xử lý để upload file lên Server của Amazon
Công cụ sử dụng:
- Rails 4.2.1
- Ruby 2.1.5
- Mysql 5.6
Let's start (honho)
1. Khởi tạo
Tạo một rails app mới
rails new dragonfly_uploader
Add gem Dragonfly
và bootstrap
gem "dragonfly"
gem "bootstrap-sass"
Các bạn nhớ bundle install
và import cho bootstrap
# stylesheets/application.scss
@import "bootstrap-sprockets";
@import "bootstrap";
Làm cái khung cho layout phát
# views/layouts/application.html.erb
<nav class="nav navbar-inverse">
<div class="container" >
<div class="navbar-header">
<%= link_to "Dragonfly", root_path, class: "navbar-brand" %>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
</ul>
</div>
</div>
</nav>
<div class="container">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>">
<%= message %>
</div>
<% end %>
<%= yield %>
</div>
Generate các file cần thiết của Dragonfly
rails g dragonfly
Sau khi chạy dòng lệnh trên, hệ thống sẽ tự động generate cho ta file config config/initializers/dragonfly.rb
Ở trong file này bạn có thể thấy có dòng
root_path: Rails.root.join('public/system/dragonfly', Rails.env)
chính là thư mục sẽ lưu trữ file upload lên mặc định. Bạn có thể đổi đường dẫn nếu muốn.
Như đã giới thiệu ở phần mở đầu, gem dragonfly
có tích hợp cả thư viện imagemagick
để xử lý ảnh.
Tuy nhiên, nếu bạn muốn sử dụng nó, cần phải add thêm dòng sau vào file config
plugin :imagemagick
Tiếp đến, chúng ta cần tạo Model và Table để lưu trữ dữ liệu. Tôi sẽ sử dụng 3 trường
title: string
: lưu tiêu đề của ảnh upload lênimage_uid: string
: lưu đường dẫn tới file ảnhimage_size: integer
: lưu thông tin về file ảnh
rails g model photo title:string image_uid:string image_size:integer
Trong model photo
mới được tạo ra, ta tích hợp nó với gem dragonfly
bằng cách thêm dòng code sau:
# photo.rb
dragonfly_accessor :image
chú ý rằng ta phải đặt tên theo đúng chuẩn của nó. Nếu bạn định nghĩa dragonfly_accessor :image
tức là nó sẽ tự động tìm đến trường trong table có tên là image_uid
.
Setup và config môi trường có vẻ đã xong xuôi (dance2)
2. Xử lý upload
Để xử lý upload, trước tiên ta generate ra controller đã, tôi đặt tên là PhotosController
.
rails g controller photos index new create
PhotosController
với 3 method là index
, new
và create
. Vậy thì cứ theo quy tắc của RESTful
mà add chức năng tương ứng vào từng method đó thôi (yaoming)
class PhotosController < ApplicationController
def index
@photos = Photo.all
end
def new
@photo = Photo.new
end
def create
@photo = Photo.new(photo_params)
if @photo.save
flash[:success] = "Photo saved!"
redirect_to photos_path
else
render :new
end
end
private
def photo_params
params.require(:photo).permit(:image, :title)
end
end
Tại trang index
sẽ show ra tất cả các Photo, trang new
sẽ là trang tạo mới và upload ảnh. Ảnh upload được save ở method create
.
Xử lý phần View một chút
Trang index
show ra list các Photos đã upload lên
# index.html.erb
<h1>List photos</h1>
<%= link_to "Upload your photo", new_photo_path, class: "btn btn-lg btn-primary" %>
<ul class="row" id="photos-list">
<% @photos.each do |photo| %>
<li class="col-xs-3">
<%= link_to image_tag(photo.image.thumb('180x180#').url, alt: photo.title, class: 'img-thumbnail'),
photo.image.url, target: '_blank' %>
<p><%= photo.title %></p>
</li>
<% end %>
</ul>
Ta add input
vào trang new
để điền title và upload file
# new.html.erb
<h1>New photo</h1>
<%= form_for @photo do |f| %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control", required: true %>
</div>
<div class="form-group">
<%= f.label :image %>
<%= f.file_field :image, required: true %>
</div>
<%= f.submit "Submit", class: "btn btn-primary btn-lg" %>
<% end %>
Về cơ bản, từ đây, ta có đã có thể upload ảnh được rồi. Tuy nhiên hiện tại chưa có validate gì đối với file upload cả. gem dragonfly
sẽ hỗ trợ đắc lực trong phần này.
Trong file config/initializers/dragonfly.rb
có đoạn
if defined?(ActiveRecord::Base)
ActiveRecord::Base.extend Dragonfly::Model
ActiveRecord::Base.extend Dragonfly::Model::Validations
end
là để extend các validate. Giờ trong model, ta chỉ cần gọi chúng ra để sử dụng.
validates :title, presence: true
validates :image, presence: true
validates :image, presence: true
validates_size_of :image, maximum: 500.kilobytes, message: "It is too big, kya!!"
validates_property :format, of: :image, in: [:jpeg, :jpg, :png, :bmp],
message: "It's not my type", case_sensitive: false
Các validation của gem dragonfly
bạn có thể tham khảo thêm ở đây
3. Xử lý ảnh
Như đã nói ở phần trên, dragonfly
tích hợp thư viện imagemagick
để xử lý ảnh.
Giả dụ như ta muốn convert tất cả các file ảnh up lên thành jpg chẳng hạn
Sử dụng callback trong model
dragonfly_accessor :image do
after_assign do |img|
img.encode!('jpg', '-quality 80') if img.image?
end
end
Hoặc như ta muốn rotate ảnh 90 độ (yaoming)
dragonfly_accessor :image do
after_assign do |img|
img.rotate!(90) if img.image?
end
end
Ngoài ra imagemagick
cũng có thể get về các thông tin về ảnh upload lên dễ dàng nhờ các method mà nó cung cấp.
Ví dụ như: image.width
, image.height
, image.aspect_ratio
, image.format
, ...
Các bạn có thể đọc thêm về các hàm ở đây
4. Kết quả upload file lên local
OK, vậy là ta đã hoàn tất việc upload ảnh lên server của chúng ta, sau đây là kết quả.
Trang index, hiển thị đường dẫn tới trang upload và hiển thị list các ảnh đã upload
Trang new, khi mà ta upload file không phải ảnh và có dung lượng quá lớn
5. Upload ảnh lên server của Amazon (Amazon S3)
S3 là dịch vụ lưu trữ dữ liệu trực tuyến của Amazon, người dùng có thể sử dụng các interface được cung cấp để lưu trữ dữ liệu server được cấp. Người dùng có thể truy cập vào dữ liệu của mình từ bất cứ nơi đâu, bất cứ lúc nào thông qua giao diện web.
Mặc định, dragonfly
sẽ upload ảnh của bạn lên local, theo đường dẫn public/system/dragonfly
.
Ở phần này, tôi sẽ hướng dẫn các bạn upload lên bên thứ 3 là server Amazon.
Để làm được điều đó, ta add thêm gem dragonfly-s3_data_store
gem "dragonfly-s3_data_store"
dragonfly
cũng có gem hỗ trợ upload lên những nơi khác như
- Dropbox: gem
dragonfly-dropbox_data_store
- Cloudinary: gem
dragonfly-cloudinary
- Couch: gem
dragonfly-couch_data_store
Và tất nhiên, để kết nối được đến Amazon S3, ta cần có tài khoản ở đó. Các bạn có thể truy cập https://aws.amazon.com/ để đăng ký tài khoản. (cần có 1 cái thẻ debit nhé (yaoming))
Sau khi tạo tài khoản thành công, bạn vào AWS management, chọn service S3 như trong hình
Tiếp tục chọn "Create Bucket", và chọn server location
Giờ hãy mở mục "Your profile - Security Credentials" -> "Access Keys" -> "Create New Access Key" -> "Download" về.
Browser sẽ down về 1 file csv
, trong đó có chứa AccessKeyID
và SecretKey
để bạn nhúng vào trong ứng dụng.
Giờ đã có đầy đủ công cụ trong tay, trong file config/initializers/dragonfly.rb
ta config lại một chút.
datastore :s3,
bucket_name: ENV["BUCKET_NAME"],
access_key_id: ENV["AWS_KEY_ID"],
secret_access_key: ENV["SECRET_KEY"],
region: "ap-southeast-1",
url_scheme: 'https'
Trong đó:
ENV["BUCKET_NAME"]
: là tên của bucket mình khởi tạo ở trong AWS management.ENV["AWS_KEY_ID"]
: làkey_id
trong file csv mình download về.ENV["SECRET_KEY"]
: làsecret_key
trong file csvregion
: là vị trí server của mình, của tôi là "ap-southeast-1"
Ở trang index hiện tại, ta đang cho url của ảnh là server local của mình, cần phải đổi lại.
<%= link_to image_tag(photo.image.thumb('180x180#').url, alt: photo.title, class: 'img-thumbnail'), photo.image.remote_url %>
Ta dùng photo.image.remote_url
thay thế cho photo.image.url
là xong.
Kết quả sau khi upload ảnh
Ta click vào ảnh mà ta upload lên S3, nó sẽ dẫn tới trang như sau
File đã được upload thành công!
GGWP (honho)
Source
Nguồn tham khảo
All rights reserved