CarrierWave bạn có thực sự biết hết tất cả cách dùng
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à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 đặtUpload 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!