Lưu trữ hình ảnh tới remote server trong Ruby on Rails với vsftpd
Khi phát triển một website chắc hẳn chúng ta quan tâm rất nhiều tới vấn đề tải lên và lưu trữ hình ảnh của người dùng. Bài viết này mình trình bày một số cách thông thường để giải quyết vấn đề này. Trong qúa trình mình làm projects đã gặp phải một vài khúc mắc, do vậy mình ghi lại bài viết để ...
Khi phát triển một website chắc hẳn chúng ta quan tâm rất nhiều tới vấn đề tải lên và lưu trữ hình ảnh của người dùng.
Bài viết này mình trình bày một số cách thông thường để giải quyết vấn đề này. Trong qúa trình mình làm projects đã gặp phải một vài khúc mắc, do vậy mình ghi lại bài viết để tiện theo dõi cho lần sau và cũng giúp cho người mới bắt đầu như mình tiếp cận dễ hơn và rút ngắn thời gian tìm hiểu.
Để tài hình ảnh lên server, Rails cung cấp một vài thư viện cho chúng ta như:
Carrierwave Gem
Paperclip Gem
Tùy từng sở thích mỗi người mà lựa chọn gem riêng cho phần này. Mình sử dụng quen thuộc gem carrierwave. Do vậy bài viết này mình sử dụng nó.
Đa số ứng dụng website đều lưu trữ hình ảnh, database và deploy code ở các server riêng để đảm bảo dễ quản lý, tăng cường bảo mật hay tăng hiệu suất hoạt động hơn cũng như giảm thiểu rủi ro hơn khi dùng chung server.
Về phần kết nối vào database server mình đã có viết một bài rồi, mọi người có thể tham khảo ở link sau Kết nối với Database trong Rails
Bài này mình trình bày về phần tải hình ảnh lên server.
Để upload hình ảnh cũng như tệp tin khác lên remote server mình sử dụng FTP. Trong ubuntu có gói phần mềm là vsftpd.
Chuẩn bị server để lưu trữ hình ảnh
Tạo người dùng mới (không nên sử dụng root), mình ví dụ tạo người dùng tên là demo.
$ ssh <remote_server> root:~# adduser demo password for `demo` ...
Tạo thư mục cho upload hình ảnh lên và gán quyền cho user.
:~# cd /home/demo/ :~# mkdir public_html/uploads -p :~# chmod 755 public_html -R :~# chown demo:demo public_html -R
Cài đặt và cấu hình vsftpd server trên ubuntu.
ssh <remote server> sudo apt-get install vsftpd
Mở file cấu hình /etc/vsftpd.conf và sửa một số dòng thông tin sau:
Việc đầu tiên cần làm là tắt quyền truy cập của anonymous user bằng cách thay đổi anonymous_enable từ yes sang no
anonymous_enable=NO
Thứ 2 cần cấp quyền tạo và ghi thư mục
bỏ comment trước local_enable và chuyển giá trị từ NO sang YES
local_enable=YES write_enable=YES
Với cấu hình như trên thì khi demo user đã có thể upload được hình ảnh cũng như tệp tin lên server rồi.
Tuy nhiên khi upload lên thì hình ảnh sẽ chịu tác động tổng hợp từ quyền cơ bản (777) với thư mục và (666) đối vơi file và một gía trị cấu hình local umask của server ftp.
Gía trị mặc định local_umask của vsftpd là 077.
Chúng ta cùng tìm hiểu về umask.
The user file-creation mode mask (umask) - đó là xác định quyền của tệp tin khi mới được tạo ra.
Quyền cơ bản của file là 0666 (hay 666) và thư mục là 0777 (hay 777).
Như vậy file và thư mục khi mới tạo ra sẽ chịu tác động tổng hợp từ base permission trên và gía trị local_umask.
Vậy cách tính quyền file và thư mục khi mới tạo ra từ 2 quyền kia như thế nào?
`quyền mới file or folder` = `base permisstion` - `local_umask`
Ví dụ khi ta set local_umask = 002 thì:
File được tạo ra sẽ có quyền là: 666 - 002 = 664.
Folder được tạo ra có quyền là: 777 - 002 = 775.
Với gía trị mặc định local_umask của vsftpd là 077, vậy file được tạo ra có quyền là 600. Do vậy khi upload hình ảnh lên server người dùng sẽ không thể xem được.
Do vậy chúng ta nên đặt local_umask là 002 hoặc 022.
Tìm kiếm tới dòng sau trong file cấu hình vsftpd và sửa lại thành như sau:
local_umask = 022
Khởi động lại vsftpd server.
service vsftpd restart
Cấu hình rails app của bạn
Chúng ta sử dụng gem sau để upload lên server đã cấu hình ở phía trên dùng ftp server.
https://github.com/luan/carrierwave-ftp
Thêm dòng sau vào Gemfile
gem 'carrierwave-ftp', :require => 'carrierwave/storage/ftp/all' # both FTP/SFTP gem 'mini_magick', '3.8.0' gem 'carrierwave', '0.10.0'
Chạy bundle install --without production để cài đặt.
Tạo file config/initializes/carrierwave.rb với thông tin như sau:
CarrierWave.configure do |config| config.ftp_host = ENV['ftp_host'] config.ftp_user = ENV['ftp_user'] config.ftp_passwd = ENV['ftp_passwd'] config.ftp_folder = "/public_html" config.ftp_url = ENV['ftp_url'] config.ftp_passive = true end
Chú ý cần export các biến environments ở trên heroku.
Tiếp theo là cấu hình carrierwave
Ở đây mình sử dụng carrierwave và tạo một uploader tên là pictures_uploader.rb có nội dung như sau:
class PictureUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick if Rails.env.production? storage :ftp else storage :file end version :medium do process resize_to_fill: [480, 360] end def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end def extension_white_list %w(jpg jpeg gif png) end end
Vậy là đã xong cấu hình cho phép user upload hình ảnh lên server remote rồi.