簡體   English   中英

Rails 4.2.x-零大小上傳的文件

[英]Rails 4.2.x - zero size uploaded files

我在視圖中顯示上傳的圖像時遇到問題。 IMO由於/public/uploads每個上傳文件的大小為零。

當前試圖在沒有任何ruby / rails gem的情況下掌握上傳和提供文件的功能。

為此,我運行了一個具有基本腳手架的原始應用程序,僅用於測試上傳/保存周期:

schema.rb:

ActiveRecord::Schema.define(version: 20151104043709) do

  create_table "uploads", force: :cascade do |t|
    t.string   "filename"
    t.string   "content_type"
    t.binary   "content"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
  end

end

UploadsController#創建:

  def create
    @upload = Upload.new(upload_params)
    data = params[:upload][:file]

    File.open(Rails.root.join('public', 'uploads', data.original_filename), 'wb') do |f|
      f.write(data.read)
    end

    respond_to do |format|
      if @upload.save
        format.html { redirect_to @upload, notice: 'Upload was successfully created.' }
        format.json { render :show, status: :created, location: @upload }
      else
        format.html { render :new }
        format.json { render json: @upload.errors, status: :unprocessable_entity }
      end
    end
  end

模型Upload.rb:

class Upload < ActiveRecord::Base
    include ActionView::Helpers::NumberHelper
    attr_accessor :upload

    def file=(upload_data)
        self.filename = upload_data.original_filename
        self.content_type = upload_data.content_type
        self.content = upload_data.read
    end

    def filename=(new_filename)
        write_attribute("filename", sanitize_filename(new_filename))
    end

private

    def sanitize_filename(filename)
        just_filename = File.basename(filename)
        just_filename.gsub(/[^\w\.\-]/, '_')
    end
end

上傳#顯示視圖:

<p id="notice"><%= notice %></p>

<p>
  <strong>Filename:</strong>
  <%= @upload.filename %>
</p>

<p>
  <strong>Content type:</strong>
  <%= @upload.content_type %>
</p>

<p>
  <%= image_tag "/public/uploads/#{@upload.filename}" %>
</p>

<%= link_to 'Edit', edit_upload_path(@upload) %> |
<%= link_to 'Back', uploads_path %> | 
<%= link_to 'Download', download_path(id: @upload) %>

問題:不好的是所有文件在/public/uploads目錄中都獲得了0個字節。

並按以下方式查看渲染: 在此處輸入圖片說明

索引視圖: 在此處輸入圖片說明

並無法加載圖像示例: 在此處輸入圖片說明

並證明所有文件均為零字節: 在此處輸入圖片說明

注意:二進制應能正常工作,因為它可以dwnl每個文件send_data

  def download
    send_data(@upload.content,
              filename: @upload.filename,
              content_type: @upload.content_type,
              )
  end

+ 在此處輸入圖片說明

========================================= 問題:什么不適合應用程序以及如何修復它以顯示圖像或視圖中的圖像? 在此先感謝您的幫助!

試試這個,我認為這應該有所幫助。

original_filename =  data.original_filename.to_s
tmp = data.tempfile
file = File.join("public/uploads", original_filename)
FileUtils.cp tmp.path, file

看起來您正在混淆兩種存儲文件的方法:

  1. 作為二進制Blob存儲在數據庫中(例如:數據庫中的content列)
  2. 將文件保存到文件系統(例如: /public/uploads/

您的實現實現了兩者的全部功能:您肯定要在uploads表的content列中將文件另存為二進制文件,並將某些內容保存到文件系統中。 您需要選擇一個。

如果你想使用方法2(文件系統),它會采取更多工作來得到它去。 如果這是您真正想要做的,請告訴我,然后我可以使用解決方案編輯答案。

但是, 方法1(數據庫)已經足夠了。 我們只需要以稍微不同的方式將各個部分放在一起。

方法1:在數據庫中存儲二進制Blob

您提到send_data對您send_data而這正是我們將用來解決您的問題的方式。

首先,將方法添加到UploadsController

def show_image
  @upload = Upload.find(params[:id])
  send_data @upload.content, type: @upload.content_type, disposition: 'inline'
end

接下來,將相應的路由添加到routes.rb

get 'show_image', to: 'uploads#show_image'

最后,在您看來,/ /uploads/show.html.erb ,將您的image_tag換成這個

<%= image_tag url_for(controller: "uploads", action: "show_image", id: @upload.id) %>

然后我們走了。 這足以使其正常工作。

我們基本上定義了一個控制器動作來從數據庫中獲取二進制blob,然后使用具有'inline'配置的send_data將文件以正確的MIME類型返回到視圖,以便視圖中的link_tag知道如何處理它。

您會注意到,您可以在UploadsControllercreate方法中刪除幾乎所有內容。 您需要的只是標准樣板代碼:

def create
  @upload = Upload.new(upload_params) # <-- All you need

  respond_to do |format|
  ...
end

您也可以刪除/public/uploads目錄,因為您沒有使用它。 該文件通過這種方法完全存儲在數據庫中,並且不會出現在文件系統中。

希望這對您有所幫助! 讓我知道這是否適合您。


關於方法2(文件系統)的注意事項:

我猜您是作為學習體驗來做的,這很棒,但是,如果您試圖將上傳的文件存儲在“真實”應用程序的文件系統中,則確實應該使用gem來處理它。 回形針使事情變得非常簡單,即使在最終將文件存儲在S3等其他地方的生產應用程序中,它也是一個有用的工具,因此學習它絕對不是浪費。

方法2 –在文件系統中存儲文件

好的,事實證明,文件系統工作的代碼實際上已經接近工作了。 主要問題在於,在upload.rbfile=(upload_data)方法中,您調用了upload_data.read 然后,在UploadsController#create ,調用f.write(data.read) 這里要注意的重要一點是dataupload_data是相同的確切文件流。 為什么這么重要?

嗯,差不多的東西read Ruby中(以及大多數其他文件的閱讀方法)是存在隱患的是跟蹤在文件流的網頁內容的“位置”的可變狀態。 (這很有用,因為大多數文件讀取都是分批完成的,例如foreach一次讀取一行。)所以file.read 真正 file.read是它“讀取了文件的其余部分”。 如果您的“位置”在開頭,那么“文件的其余部分”就是整個文件。 但是,如果您走了一半,那么“其余”只是下半部分。 因此,“當前位置”在read -ing時總是在文件的最后結束,這意味着(除非我們“后退”)任何以后的read調用都將返回空字符串,因為沒有更多內容了“文件的其余部分”。 例:

myfile = File.open(some_path_to_file, 'r')
myfile.read
  # => "lorem ipsum..." # (file contents from beginning)
myfile.read
  # => ""  # (empty string)
myfile.rewind
  # => 0 (resets 'position' to position 0, the beginning)
myfile.read
  # => "lorem ipsum..." # (file contents from beginning)

(好的,如果您想在閱讀答案之前先嘗試一下,那么這足以為您解決問題提供幫助。如果沒有,或者准備就緒,請繼續閱讀...)

upload.rb ,進行以下更改file =(upload_data)

def file=(upload_data)
  self.filename = upload_data.original_filename
  self.content_type = upload_data.content_type
  self.content = upload_data.read # <-- Either Delete this line, OR
  upload_data.rewind              # <-- Add this line
end

顯然,在實際的應用程序中,我們將刪除self.content行,因為我們正嘗試使用文件系統來實現方法2,但是由於這是一個測試應用程序,因此您可以完全同時工作。 為此,只需在末尾添加upload_data.rewind行。

因此,現在create方法應該可以將文件成功添加到您的/public/uploads目錄(它們將不再為空),因此請檢查以確保工作正常。 接下來,我們只需要確保正確設置視圖即可。

show.rb ,圖像標簽應如下所示

<%= image_tag "/uploads/#{@upload.filename}" %>

您使用/public/uploads/...而不是/uploads/... 出於安全原因, image_tag只能在/public內部查看,因此您不必在路徑中指定'/ image_tag它會自動添加。

並且,我們完成了! 請讓我知道這對你有沒有用。

更多

您可能還應該做幾件事。 像稍微修改create動作:

File.open(Rails.root.join('public', 'uploads', data.original_filename), 'wb') do |f|
  f.write(data.read)
  f.close # <-- add this line. You should always explicitly close file streams after you open them.
end

#### something else here

另外,與其像我們這樣對路徑進行硬編碼,不如將路徑存儲在數據庫中的file_path列中,然后我們可以將@upload.file_path傳遞給image_tag

rails g migration AddFilePathToUploads file_path:string
rake db:migrate

然后確保我們的create動作在保存之前手動設置路徑。 因此,請插入以下內容,而不是“此處還有其他內容”

@upload.file_path = ['/uploads', data.original_filename].join '/'

然后在show.rb更改圖像標簽

<%= image_tag @upload.file_path %>

好了, 現在我們就大功告成了。 我只想再次提出建議,以檢出Paperclip或CarrierWave寶石,因為它們可能是您在任何實際項目中都會使用的寶石。

希望您學到了一些東西,對您有所幫助。 我也很開心。 讓我知道您何時開始工作!

干杯

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM