+4

Tìm hiểu về gem PaperClip

Tổng quan Hiện nay, có nhiều ứng dụng web cho phép người dùng upload image và các loại file khác để lưu trữ và xử lý. PaperClip là một thư viện ruby đã lược bỏ những quá trình phức tạp, và giúp chúng ta dễ dàng hơn trong việc upload file. Không chỉ với local mà còn với các nơi lưu trữ bên ngoài khác như Amazon S3 or Rackspace CloudFiles. Việc này nhằm tách biệt các file ứng dụng và code của bạn. Paper Clip xử lý các file như là một thuộc tính model. Không dài dòng, sau đây mình sẽ giới thiệu và cấu hình để ứng dụng web của chúng ta có thể upload file lên Amazon S3 với gem paperclip. Cấu hình Ngoài việc dùng gem paperclip chúng ta cần sử dụng thêm gem aws-sdk.

Gemfile

gem "paperclip" gem "aws-sdk", "~> 2.3" chạy bundle install và khởi động lại server rails sau khi chỉnh sửa gemfile. Chúng ta cũng cần chỉ rõ việc cấu hình để có thể thao tác với AWS. Trước khi cấu hình thì các bạn cần có tài khoản AWS và tạo một bucket nơi mà sẽ lưu trữ những file chúng ta cần upload. Do bên AWS sẽ cho chúng ta tạo tài khoản và dùng miên phí một số dịch vụ trong vòng 1 năm nên bạn nào muốn test thì thử nhé. Hướng dẫn chi tiết đăng kí tài khoản các bạn có thể xem ở link sau. Tiếng việt cho người việt 😄 hướng dẫn đăng kí aws free 1 năm. Sau khi có được tài khoản bạn lấy Secret Access Key theo hướng dẫn này. Tạo một bucket trên s3. Khi đã có 3 đủ các thông tin trên ta cấu hình: [code]

config/environments/production.rb

config.paperclip_defaults = {
    path: ":attachment/:id/:style/:custom_filename",
    storage: :s3,
    url: ":s3_alias_url",
    s3_headers: lambda { |attachment|
      {
        "Content-Type": "application/octet-stream",
        "server_side_encryption": "AES256",
      }
    },
    s3_host_alias: "#{ENV['BUCKET']}.s3.amazonaws.com",
    s3_permissions: "public_read",
    s3_protocol: "https",
    s3_credentials: {
      bucket: ENV["BUCKET"],
      access_key_id: ENV["ACCESS_KEY_ID"],
      secret_access_key: ENV["SECRET_ACCESS_KEY"],
      s3_region: ENV["S3_REGION"],
    }
  }

Mình sẽ giải thích một số config ở trên. các config ở trên có thể được viết trong model cùng với has_attached_file. ví dụ:

#model friend
class Friend < ActiveRecord::Base
  has_attached_file :foto,
    :default_url => '/images/foto.jpg',
    :default_style => :medium,
    :use_timestamp => false,
    :url => '/system/:access_token/foto_:style.:extension',
    :path => ':rails_root/public:url',
    :styles => { :medium => "470x320", :small => "162x107" }
end

Bạn để ý ở path trên mình có dùng :custom_filename. Cái được đinh nghĩa

# config/initializers/paperclip.rb
require "digest/sha1"

Paperclip.interpolates :custom_filename do |attachment, style|
    if attachment.instance.created_at < ENV["TIME_CONFIG_UPLOAD"]
      Digest::SHA1.hexdigest "#{attachment.original_filename}-#{attachment.updated_at}"
    else
      attachment.original_filename
    end
end

Paperclip.interpolates nhằm mục đích làm cho đường dẫn linh hoạt hơn. Ở trên mình đã dùng sha1 để băm file name của mình ra. khi đó đường dẫn sẽ có dạng https://s3.amazonaws.com/namebuffetbucket/attachments/41/original/f2fbb3492703bc9464b2015957cc273e410f8e3d. Ở trên mình có set thêm s3_headers để thay đổi conten type của file, và server side encryption, nếu bạn không set server_side_encryption thì mặc định trên aws sẽ là none. Một cái quan trọng nữa là s3_permissions. Cái này dùng để phân quyền xem ai có thể truy nhập và thao tác với file của bạn, khi bạn đưa link cho họ. Ví dụ như download chẳng hạn. Có rất nhiều quyền hạng, bạn có thể đọc thêm tại đây. Định nghĩa thuộc tính file trong Model Thêm vào trong model method helper "has_attached_file" và tên của attachment file mà mình mong muốn.

class Friend < ActiveRecord::Base
  # This method associates the attribute ":avatar" with a file attachment
  has_attached_file :avatar, styles: {
    thumb: '100x100>',
    square: '200x200#',
    medium: '300x300>'
  }

  # Validate the attached image is image/jpg, image/png, etc
  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end

has_attached_file cũng cho phép định nghĩa một hash styles để chỉ rõ việc resize upload. ">" và "#" sẽ cho ImageMagick biết image sẽ được resize thế nào. ">" tương ứng với việc giảm kích thước của image. Update database Database cần thêm avatar cho friend in database schema.

rails g migration AddAvatarToFriends

paperclip đi kèm với migration helper method add_attachment và remove_attachment. sử dụng chúng trong migration vừa tạo ra:

class AddAvatarToFriends < ActiveRecord::Migration
  def self.up
    add_attachment :friends, :avatar
  end

  def self.down
    remove_attachment :friends, :avatar
  end
end

Nó sẽ tạo ra trong db:: avatar_file_name avatar_file_size avatar_content_type avatar_updated_at trong model Friend. 4 thuộc tính trên sẽ được set mặc định khi file được upload. Giờ chạy rake db:migrate với rails 4. rails db:migrate với rails > 5.0. Upload form

<%= form_for(@friend, multipart: true) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :avatar %>
    <%= f.file_field :avatar %>
  </div>
  <div class="actions">
    <%= f.submit 'Make a friend' %>
    <%= link_to 'Nevermind', friends_path, class: 'button' %>
  </div>
<% end %>

Upload controller

class FriendsController < ApplicationController
  # Other CRUD actions omitted

  def create
    @friend = Friend.new(friend_params)

    if @friend.save
      redirect_to @friend, notice: 'Friend was successfully created.'
     else
       render action: 'new'
    end
  end

  private

  def friend_params
    params.require(:friend).permit(:avatar, :name)
  end
end

Các file lớn hơn 4Mb sử dụng upload trực tiếp có thể dẫn tới tình trạng time out.Nên đối với các file lớn thì dùng direct upload Image display Truy cập file thông qua url

friend.avatar.url #=> http://your_bucket_name.s3.amazonaws.com/...

ví dụ:

<%= image_tag @friend.avatar.url(:square) %>
<%= image_tag @friend.avatar.url(:medium) %>

với square, medium mình đã định nghĩa trên style. Tổng Kết Ở trên thì mình đã có giới thiệu cách cấu hình để một ứng dụng rails có thể upload file lên AWS s3. Hi vọng nó có ích với các bạn. Cảm ơn khi đọc bài của mình.

Tài liệu tham khảo https://github.com/thoughtbot/paperclip https://devcenter.heroku.com/articles/paperclip-s3 http://www.rubydoc.info/gems/paperclip/Paperclip/Storage/S3


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.