Upload Files to Database in Rails 4 Without Paperclip
I. Giới thiệu Như đã biết thì gem Paperclip là một gem rất hữu dụng trong các app Rails nhưng nó không support cho việc save file vào trong database. Trong một số tình huống, truy cấp vòa filesystem hoặc dịch vụ bên ngoài như Amazon S3 thì không được khả thi. Hoặc đơn giản là muố đưa các files ...
I. Giới thiệu
Như đã biết thì gem Paperclip là một gem rất hữu dụng trong các app Rails nhưng nó không support cho việc save file vào trong database. Trong một số tình huống, truy cấp vòa filesystem hoặc dịch vụ bên ngoài như Amazon S3 thì không được khả thi. Hoặc đơn giản là muố đưa các files vào trong cơ sở dữ liệu.
II. Hướng dẫn cách làm
- Đầu tiên, tạo một model để lưu thông tin file.
- filename:string - content_type:string - fine_contents:binary
-
Note: để tạo nhanh 1 model như trên ta có thể sử dụng: rails g scaffold document filename:string content_type:string file_contents:binary
-
Dưới đây là: code for model và file migration
# app/models/document.rb class Document < ActiveRecord::Base end # db/migrate/20140602005921_create_documents.rb class CreateDocuments < ActiveRecord::Migration def change create_table :documents do |t| t.string :filename t.string :content_type t.binary :file_contents t.timestamps end end end
- Tiếp theo chúng ta sẽ thêm file input cho model's form
<!-- app/views/documents/_form.html.erb --> <%= form_for(@document) do |f| %> <div class="field"> <%= f.file_field :file %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
- Tiếp đến, chúng ta cần đảm bảo rằng phải permit params[:file], bởi thế chúng ta mới sử dụng được file trong model
# app/controllers/documents_controller.rb def document_params params.require(:document).permit(:file) end
- Cuối cùng update cho model có thể đọc và lưu file lại. Ở trong Rails, thì file input được passed như là một UploadedFile, có thể coi nó như một normal file. Chúng ta sẽ viết một hàm initialize trong model:
# app/models/document.rb def initialize(params = {}) file = params.delete(:file) super if file self.filename = sanitize_filename(file.original_filename) self.content_type = file.content_type self.file_contents = file.read end end private def sanitize_filename(filename) # Get only the filename, not the whole path (for IE) # Thanks to this article I just found for the tip: http://mattberther.com/2007/10/19/uploading-files-to-a-database-using-rails return File.basename(filename) end
- Bây giờ chúng ta có một app mà ở đó users có thể upload files lên, nhưng vẫn chưa thể download được. Chúng ta có thể tao ra show action trong documents_controller để download file. Để làm như vậy chỉ cận gửi các file đã lưu trong DB.
def show send_data(@document.file_contents, type: @document.content_type, filename: @document.filename) end
- Okey. Giờ chúng ta đã có 1 app Rails có thể upload và download file 1 cách rất đơn giản. Chúng ta có thể viết validate cho việc upload file, ví dụ như MB size, name ...
# app/models/document.rb validate :file_size_under_one_mb def initialize(params = {}) # File is now an instance variable so it can be # accessed in the validation. @file = params.delete(:file) super if @file self.filename = sanitize_filename(@file.original_filename) self.content_type = @file.content_type self.file_contents = @file.read end end NUM_BYTES_IN_MEGABYTE = 1048576 def file_size_under_one_mb if (@file.size.to_f / NUM_BYTES_IN_MEGABYTE) > 1 errors.add(:file, 'File size cannot be over one megabyte.') end end
- Vừa rồi chúng ta vừa tạo ra một application Rails có thể upload và download file.
- Link APP DEMO
- Source GITHUB