Uploads file with CarrierWave in rails
1.Giới thiệu CarrierWave - một tiện ích hỗ trợ việc tải các tập tin một cách linh hoạt với nhiều khả năng và sự chỉnh sửa ,nó được trang bị khá tốt cho việc tải lên tất cả các định dạng loại tập tin .Khi xây dựng ứng dụng của riêng bạn , những hình ảnh đẹp hay những tập tin quan trọng của bạn ...
1.Giới thiệu
CarrierWave - một tiện ích hỗ trợ việc tải các tập tin một cách linh hoạt với nhiều khả năng và sự chỉnh sửa ,nó được trang bị khá tốt cho việc tải lên tất cả các định dạng loại tập tin .Khi xây dựng ứng dụng của riêng bạn , những hình ảnh đẹp hay những tập tin quan trọng của bạn có thể được lưu trữ ngay trên ứng dụng của bạn hoặc lưu trữ bên ngoài giống như các máy chủ Amazone hay iCloud.
2.Cài đặt
Để bắt đầu việc sử dụng CarrierWave, trong gemfile của bạn , hãy thêm gem "carrierwave" và chạy bundle install
gem 'carrierwave', '~> 1.0'
Đối với version 1.0, CarrierWave yêu cầu phiên bản Rails 4.0 trở lên và Ruby 2.0 trở lên , nếu bạn đang sử dụng Rails 3.0 thì nên sử dụng gem với phiên bản v0.11.0.
3. Xây dựng ứng dụng đơn giản cho phép upload ảnh, tập tin
CarrierWave làm việc thông qua một class của Ruby goi là Uploader vì thế chúng ta sẽ bắt đầu bằng cách chạy lệnh :
$ rails generate uploader Avatar
Sau khi chạy lệnh sẽ tạo ra file 'image_uploader.rb' (trong thư mục Uploader) ở trong thư mục app của ứng dụng :
app/uploaders/avatar_uploader.rb
Tại đây bạn có thể customize việc upload file :
class AvatarUploader < CarrierWave::Uploader::Base storage :file end
CarrierWave cung cấp cho bạn 1 kho chứa để lưu trữ vĩnh viễn và 1 bộ nhớ cache để lưu trữ tạm thời .Bạn có thể sử dụng các kho chứa khác nhau bao gồm filesystem và cloud storage. Tiến hành xây dựng một chức năng đơn giản ,cho phép upload tập tin cho Category: Step1: Khởi tạo model Category:
rails generate model category title:string
Step2: Khởi tạo model CategoryAttachment
rails generate model category_attachment category_id:integer attachment:string rake db:migrate
Step3: in Category.rb
class Category < ActiveRecord::Base has_many :category_attachments accepts_nested_attributes_for :category_attachments end
in CategoryAttachment.rb
class CategoryAttachment < ActiveRecord::Base mount_uploader :attachment, Uploader belongs_to :category end
In Category_controller.rb
def new @category = Category.new @category_attachment = @category.category_attachments.build end def create @category = Category.new(category_params) if @category.save params[:category_attachments]['attachment'].each do |a| @category_attachment = @category.category_attachments.create!(attachment: a) end redirect_to @category else render :new end end private def category_params params.require(:category).permit(:title, category_attachments_attributes: [:id, :category_id, :attachment]) end
in views/categories/_form.html.erb
<%= form_for(@category, :html => { :multipart => true }) do |f| %> <div class="field"> <%= f.label :title %><br> <%= f.text_field :title %> </div> <%= f.fields_for category_attachments do |p| %> <div class="field"> <%= p.label :attachment %><br> <%= p.file_field :attachment, :multiple => true, name: "category_attachments[attachment][]" %> </div> <% end %> <div class="actions"> <%= f.submit %> </div> <% end %>
4 .Multiple file uploads Để sử dụng được tính năng này bạn cần add thêm gem file ở nhánh master :
gem 'carrierwave', github: 'carrierwaveuploader/carrierwave'.
Trong database chúng ta cần thêm một cột mà có thể lưu trữ mảng , cột này có thể là mảng hoặc dạng json tùy thuộc vào sự hỗ trợ của CSDL.Ví dụ:
rails g migration add_avatars_to_users avatars:json
Tiếp đến bạn cần chắc chắn input field của bạn là multiple file field, và giá trị permit trong controller của bạn là mảng trống trong 1 hash:
<%= form.file_field :avatars, multiple: true %> params.require(:user).permit(:email, :first_name, :last_name, {avatars: []})
Bây giờ bạn có thể lựa chọn nhiều file upload và chờ nó được tụ động lưu trữ khi bản khi được lưu.
5.Thay đổi thư mục lưu trữ Để thay đổi được vị trí lưu trữ file upload , chúng ta cần thay đổi phương thức store_dir như ví dụ sau:
class Uploader < CarrierWave::Uploader::Base def store_dir 'public/my/upload/directory' end end
Bạn cũng có thể định nghìa store_dir như là nil nếu bạn muốn lưu trữ file ngay lại folder gốc trong dự án của bạn.Ngoài ra nếu bạn muốn lưu trữ chúng ở ngoài dự án , bạn có thể dùng phương thức cache_dir:
class Uploader < CarrierWave::Uploader::Base def cache_dir '/tmp/projectname-cache' end end
6.Securing uploads Một số tập tin sẽ gây nghuy hiểm nếu tải lên vị trí sai, ví dụ như các tập tin PHP hay các tập tin khác , carrierwave cho phép bạn quyết định phần mở rộng các tập tin tải lên ,nếu bạn cố gắng tải một tập tin sai thì một thông báo lỗi sẽ được đưa lên:
class Uploader < CarrierWave::Uploader::Base def extension_whitelist %w(jpg jpeg gif png) end end
Hoặc là chỉ chấp nhận nội dung là hình ảnh
class Uploader < CarrierWave::Uploader::Base def content_type_whitelist /image// end end
Hoặc bạn có thể lập ra 1 danh sách đen để từ chỗi các loại nội dung mà bạn mong muốn , nếu muốn từ chối tập tin dạng JSON , chúng ta có thể làm như thế này :
class NoJsonUploader < CarrierWave::Uploader::Base def content_type_blacklist ['application/text', 'application/json'] end end
7.Filenames and unicode chars Một vấn đề về bảo mật mà bạn cần được quan tâm đó là tên của các tập tin .Theo mặc định thì CarrierWave chỉ cung cấp tên theo chữ cái tiếng anh , chữ số arabic và một vài kí tự trắng , nếu bạn muốn được hỗ trợ dạng chữ địa phương thì chúng ta cần đến phương thức sanitize_regexp :
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:].-+]/
8.Xóa file upload CarrierWave cho phép xóa file một cách dễ dàng với việc dùng checkbox field:
<%= form_for @user, html: { multipart: true } do |f| %> <p> <label>My Avatar</label> <%= image_tag(@user.avatar_url) if @user.avatar? %> <%= f.file_field :avatar %> </p> <p> <label> <%= f.check_box :remove_avatar %> Remove avatar </label> </p> <% end %>
Bằng cách gọi remove_avatar!, sau đó lưu lại:
@user.remove_avatar! @user.save
9.Thêm version Khi ảnh được tải lên có kích thước quá lớn ,chúng ta có thể thay đổi kích cỡ của bức ảnh bằng cách dùng gem 'mini_magick'
class Uploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick process resize_to_fit: [800, 800] version :thumb do process resize_to_fill: [200,200] end end