Viblo Learning
+2

Upload image với gem CarrierWave

Gem CarrierWave hỗ trợ upload tập tin và hình ảnh một cách đơn giản và linh hoạt đối với các ứng dụng Ruby.

  • Cài đặt:

Cũng như các gem khác, để cài đặt chúng ta thêm gem CarrierWave vào trong Gemfile và sau đó bundle install.


gem 'carrierwave'
  • Để hiểu rõ về phương thức hoạt động và cách sử dụng của gem carrierwave chúng ta sẽ đi vào làm một ví dụ xây dựng 1 web cho phép người dùng tự tạo album, upload photo vào album đó.

Database:

  create_table "albums", force: true do |t|
    t.string "name"
  end

  create_table "photos", force: true do |t|
    t.string  "name"
    t.integer "album_id"
  end
  • CarrierWave cung cấp 1 thư viện uploader. Để sử dụng thư viện này ta generate, dùng câu lệnh trong Terminal:
$ rails generate uploader image
    create  app/uploaders/image_uploader.rb

Kiểm tra trong thử mục app/uploaders xuất hiện file image_uploader.rb.


class ImageUploader < CarrierWave::Uploader::Base
  storage :file
end

Tiếp theo chúng ta kết nối image với model Photo (mỗi photo thì có file image tương ứng). Thêm thuộc tính image vào bảng Photo:

$ rails g migration add_image_to_photos image:string

Mở file /app/models/photo.rb thêm các attr_accessible, quan hệ belongs_to đối với album và liên kết image với ImageUploader:


class Photo < ActiveRecord::Base
  attr_accessible :album_id, :name, :image
  belongs_to :album
  mount_uploader :image, ImageUploader
end

Trong file view chúng ta sử dụng form_for cho @photo, thêm :html => {:multipart => true} để có thể upload file.


<%= form_for @photo, :html => {:multipart => true} do |f| %>
  <%= f.error_messages %>
  <%= f.hidden_field :album_id %>
  <p>
    <%= f.label :name %>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.file_field :image %>
  </p>
  <p><%= f.submit %></p>
<% end %>

Để hiển thị hình ảnh ra màn hình, chúng ta có thể sử dụng image_tag với link của photo là image_url, thêm to_s để tránh trường hợp không có ảnh giá trị trả về sẽ là nil:


<%= image_tag photo.image_url.to_s %>
  • Tuy nhiên, nếu để thế này thì ảnh sẽ được hiển thị ở cỡ thực có thể to quá hoặc bé quá. ImageUploader có thể giúp chúng ta vẫn giữ ảnh gốc và sao lưu ra các phiên bản ảnh khác với các kích thước chúng ta mong muốn.

Cài đặt thêm gem mini_magick vào Gemfile để có thể thay đổi kích thước của ảnh (một số tài liệu hướng dẫn có thể thêm gem rmagick).

Trong image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  process resize_to_fit: [800, 800]

  version :thumb do
    process resize_to_fill: [200,200]
  end
end

Khi ảnh được tải lên, giá trị kích thước mặc định là chiều dài, chiều rộng không quá 800px. Còn version thumb, ảnh được tải lên và crop về size 200px, 200px. Có thể tạo nhiều version.

photo.url # size: 800x800
uploader.thumb.url # size: 200x200
  • Ở trên là cách upload ảnh có sẵn trong máy tính, chúng ta cũng có thể upload bằng url của ảnh.

Trong model photo.rb thêm attr_accessible :remote_image_url.

File view, trong form_for thêm

  <p>
    <%= f.label :remote_image_url, "upload by image URL" %>
    <%= f.text_field :remote_image_url %>
  </p>

Chúng ta chỉ việc paste link và ảnh được tải lên 1 cách dễ dàng.

  • Để xoá file ảnh, ta chỉ cần gọi method remove_image sau đó save.
<%= f.check_box :remove_image %>Xóa ảnh
@photo.remove_image!
@photo.save
#=> true
  • CarrierWave còn cho phép người dùng giới hạn kiểu file nhất định để được tải lên.

class ImageUploader < CarrierWave::Uploader::Base
  def extension_white_list
    %w(jpg jpeg gif png)
  end
end

Phía trên là người dùng chỉ được phép tải ảnh có đuôi là : .jpg, .jpeg, .gif hoặc .png

  • Trong trường hợp ảnh tải lên bị lỗi, carrierwave cũng hỗ trợ xác định các url mặc định để thay thế:

image_uploader.rb


class ImageUploader < CarrierWave::Uploader::Base
  def default_url(*args)
    '/images/fallback/' + [version_name, 'default.png'].compact.join('_')
  end
end

Kết: Với Gem CarrierWave việc upload ảnh trở nên thật dễ dàng 😃. Ngoài ra còn có các gem Paperclip, Dragonfly,...

Tài liệu tham khảo:


All Rights Reserved