CarrierWave bạn có thực sự biết hết tất cả cách dùng
Bài đăng này đã không được cập nhật trong 6 năm
Chào các bạn, CarrierWave
là một gem hỗ trợ đến upload file trong ruby. Khi tìm kiếm trên viblo bạn sẽ thấy rất nhiều bài viết được giới thiệu cũng như sử dụng.
Tuy nhiên khi mình đọc thì có rất nhiều phần được ghi trong document lại không được nhắc tới và trong bài viết này mình sẽ điểm qua một số chỗ mình nghĩ sẽ hấp dẫn bạn...
Cài đặt
Upload file và lưu file vào model
- Upload nhiều file và lưu vào model.
- Thay đổi thư mục lưu
Bảo mật khi upload- Cung cấp một địa chỉ lưu file default
Cấu hìnhTestUpload lên AWS hoặc tương tự18n
- Large files
- Skipping ActiveRecord callbacks
- Vấn đề mình gặp phải => dẫn tới bài viết này
Có những phần màu đỏ mà được gạch ngang là phần này bạn hoàn toản có thể tìm kiến trên viblo có rất nhiều bài viết. Những phần màu đen gạch ngang phần này mình không chắc chắn và chưa thử trên thực tế bạn có thể đọc tại document. Và sau đây, ta cùng bắt đầu...
3. Upload nhiều file và lưu vào model
CarrierWave
có hỗ trợ định nghĩa upload nhiều file 1 lúc. Tuy nhiên, trong phần này mình nghĩ chỉ có một điều cần chú ý đó là:
CarrierWave
sẽ lưu trong model của bạn là định dang array. Tuy nhiên không phải bất kỳ CSDL nào cũng tương thích với kiểu data loại này.
VD như: mysql, PostgreSQL thì có thể tương thích với loại dữ liệu json còn SQLite
thì lại không vì thế với mysql, PostgreSQL
bạn hoàn toàn có thể tạo record với format:
rails g migration add_avatars_to_users avatars:json
rake db:migrate
Còn SQLite
thi nên là:
rails g migration add_avatars_to_users avatars:string
rake db:migrate
Khi đấy trong model ta cần config sẽ khác
class User < ActiveRecord::Base
mount_uploaders :avatars, AvatarUploader
serialize :avatars, JSON # If you use SQLite, add this line.
end
Như đoạn code trên t thấy rằng với kiểu dữ liệu string thì bắt buộc cần thêm dòng serialize :avatars, JSON
để định nghĩa dữ liệu đầu ra sẽ theo dạng serialize
.
Theo như vậy thì chúng ta cần config 1 kiểu dữ liệu mà tất cả CSDL đều có để tránh trường hợp code của mình chỉ chạy trên một môi trường csdl thì mình nghĩ nên để kiểu dữ liệu String
vì tất cả CSDL đều hỗ trợ.
4. Thay đổi thư mục lưu
Để config lại nơi lưu ta cần thay override function store_dir
.
Mặc định thì khi upload file, file của chúng ta sẽ được lưu trong thư mục "public/upload"
tuy nhiên bây giờ bạn lại muốn dễ dàng quản lý file hơn.
Thí dụ, khi bạn muốn thư mục file về user
sẽ chỉ ở thư mục của user
, thư mục của sản phẩm sẽ ở thư mục của sản phẩm.
Thì phần này sẽ giúp bạn cần thiết.
class MyUploader < CarrierWave::Uploader::Base
def store_dir
'public/my/upload/directory'
end
end
Bạn có thể định nghĩa store_dir
return nil
nếu như bạn muốn lưu file ở thư mục gốc.
Còn nếu bạn muốn lưu file không thuộc thư mục dự án, mà ở chỗ nào khác thì bạn cần config cache_dir
.
class MyUploader < CarrierWave::Uploader::Base
def cache_dir
'/tmp/projectname-cache'
end
end
6. Cung cấp một địa chỉ lưu file default
Trong nhiều trường hợp khi bạn tạo một đối tượng mà muốn có dữ liệu file default được lưu trong model, mà không phải là ở trạng thái null
thì đây là cách carrierwave
hỗ trợ.
class MyUploader < CarrierWave::Uploader::Base
def default_url(*args)
"/images/fallback/" + [version_name, "default.png"].compact.join('_')
end
end
11. Large files
Mặc định thì CarrierWave copy 1 file 2 lần, lần đầu tiên thì file sẽ được copy vào cache, lần 2 sẽ được copy vào nơi lưu trữ.
Vì vậy, với 1 file lớn chúng ta sẽ mất nhiều thời gian cho việc lưu trữ. Vì thế, bạn có thể change hành động này bằng cách overriding
2 function move_to_cache
vs move_to_store
.
class MyUploader < CarrierWave::Uploader::Base
def move_to_cache
true
end
def move_to_store
true
end
end
12. Skipping ActiveRecord callbacks
Mặc định khi gắn uploader
vào active record thì nghĩa là chúng ta đã thêm các callbacks vào trong model.
class User
mount_uploader :avatar, AvatarUploader
end
=>
class User
................................
after_save :store_avatar!
before_save :write_avatar_identifier
after_commit :remove_avatar!, on: :destroy
after_commit :mark_remove_avatar_false, on: :update
after_save :store_previous_changes_for_avatar
after_commit :remove_previously_stored_avatar, on: :update
end
Nếu bạn muốn bỏ qua bất kỳ callbacks nào bạn có thể sử dụng phương thức skip_callback của ActiveRecord.
class User
mount_uploader :avatar, AvatarUploader
skip_callback :commit, :after, :remove_previously_stored_avatar
end
13. Vấn đề mình gặp phải => dẫn tới bài viết này
Bài viết này mình nghĩ rằng nên viết vì mình đã mắc sai lầm khi chưa thực sự hiểu về CarrierWave
vì mình gặp được 1 yêu cầu:
Khi mình tạo ra 1 file ảnh bằng code => lưu file này vào vị trí "X" nào đó => lấy ra file vào thời điểm nào đó => có thể lấy lại tất cả file đã lưu. Code của mình được deploy ở nhiều server tuy nhiên khi tạo ảnh mình chỉ muốn lưu ở trong serve của mình và chỗ nào thuộc serve cũng gọi được.
Tuy nhiên, do trước đây mình chưa tìm hiểu kỹ hết về CarrierWave
nên thời điểm làm đã gặp sai lầm.
Kết luận
Hi vọng bài viết sẽ hữu ích cho bạn !!
Thanks for your reading!
All rights reserved