2016-04-28 63 views
0

我在Rails應用程序中使用Paperclip來驗證文件附件並將它們加載到AWS S3中。期望的行爲是用戶在提交記錄表單時能夠上傳多個「RecordAttachments」(文件附件)。Rails:在保存父項之前保存子元素

問題在於,只要用戶選擇要使用文件選擇器上載的文件,無論用戶是否提交了「記錄」表單,我都希望立即開始上傳RecordAttachments。我也想確保每個RecordAttachment都被映射到它所屬的記錄。這一定是可能的,但我還不確定如何構建邏輯。

目前,我可以允許用戶在填寫並提交記錄表單時創建多個RecordAttachments,但我想立即開始上傳文件,以便我可以向用戶顯示錶單頁面上的每個上載進度。下面是允許用戶提交多個RecordAttachments一個記錄代碼:

#app/models/record.rb 
class Record < ActiveRecord::Base 
    has_many :record_attachments 
    accepts_nested_attributes_for :record_attachments 

    # Ensure user has provided the required fields 
    validates :title, presence: true 
    validates :description, presence: true 
    validates :metadata, presence: true 
    validates :hashtag, presence: true 
    validates :release_checked, presence: true 

end 

並且子元素:

#app/models/record_attachment.rb 
class RecordAttachment < ActiveRecord::Base 
    belongs_to :record 
    validates :file_upload, presence: true 

    # Before saving the record to the database, manually add a new 
    # field to the record that exposes the url where the file is uploaded 
    after_save :set_record_upload_url 

    # Use the has_attached_file method to add a file_upload property to the Record 
    # class. 
    has_attached_file :file_upload 

    # Validate that we accept the type of file the user is uploading 
    # by explicitly listing the mimetypes we are willing to accept 
    validates_attachment_content_type :file_upload, 
    :content_type => [ 
     "video/mp4", 
     "video/quicktime" 
    ] 
end 

記錄控制器:

class RecordsController < ApplicationController 
    # GET /records/new 
    def new 
    @record = Record.new 
    end 

    def create 
    # retrieve the current cas user name from the session hash 
    @form_params = record_params() 
    @form_params[:cas_user_name] = session[:cas_user] 
    @record = Record.create(@form_params) 

    respond_to do |format| 
     if @record.save 
     if params[:record_attachments] 
      params[:record_attachments].each do |file_upload| 
      @record.record_attachments.create(file_upload: file_upload) 
      end 
     end 

     flash[:success] = "<strong>CONFIRMATION</strong>".html_safe + 
      ": Thank you for your contribution to the archive." 
     format.html { redirect_to @record } 
     format.json { render action: 'show', 
      status: :created, location: @record } 
     else 
     format.html { render action: 'new' } 
     format.json { render json: @record.errors, 
      status: :unprocessable_entity } 
     end 
    end 
    end 
end 

我的形式如下:

<%= form_for @record, html: { multipart: true } do |f| %> 
    <div class="field"> 
    <%= f.label :title, "Title of Material<sup>*</sup>".html_safe %> 
    <%= f.text_field :title %> 
    </div> 
    <!-- bunch of required fields followed by multiple file uploader: --> 
    <div id="file-upload-container" class="field"> 
    <%= f.label :file_upload, "Upload File<sup>*</sup>".html_safe %> 
    <div id="placeholder-box">File name...</div> 
    <%= f.file_field :file_upload, 
     multiple: true, 
     type: :file, 
     name: 'record_attachments[]', 
     id: "custom-file-upload", 
     style: "display:none" 
    %> 
    <span class="btn btn-small btn-default btn-inverse" id="file-upload-button" onclick="$(this).parent().find('input[type=file]').click();">Browse</span> 
    </div> 

    <!-- bunch of fields followed by submit button --> 
    <%= button_tag(type: 'submit', class: "btn btn-primary blue-button submit-button") do %> 
    <i class="icon-ok icon-white"></i> SUBMIT 
    <% end %> 
<% end %> 

考慮到此設置,是否有人知道任何方法,只要用戶選擇它們就可以開始上傳RecordAttachments,而不是在他們提交記錄表單時?

在用下面的@ShamSUP對此進行了說明之後,以下是我的想法:在頁面加載時,檢查用戶是否有Record_id爲零的任何RecordAttachments。如果是這樣,請刪除它們。然後用戶選擇一個或多個文件。對於每一個,將recordAid設置爲nil的RecordAttachment表中保存一行。然後,如果/當用戶成功提交其記錄表單時,找到所有具有record_id == nil的用戶的RecordAttachments,並將每個record_id設置爲當前Record的id。

這似乎是一個合理的解決方案嗎?有更好/更簡單的方法嗎?我非常感謝他人在這個問題上提供的任何幫助!

回答

0

我最終使用了ng-file-upload,這是一個非常棒的文件上傳庫,用於Angular.js。 full source可用於其他人最終需要在保存父記錄之前保存子節點的情況,但是最重要的是您希望將子節點從Javascript寫入數據庫,然後一旦保存父節點,就更新parent_id元素的每個孩子。

0

Javascript無法實際讀取文件輸入字段中的文件內容,因此不幸的是無法在用戶嘗試填寫表單的其餘部分時通過ajax提交。但這並不意味着你不能執行一些迂迴的方法。

你可以嘗試的東西是在表單頁面加載時生成記錄ID,然後在主表單中的隱藏輸入中包含id,並將文件輸入放在單獨的表單中,或將它們移動到單獨的表單中與頁面加載後的JavaScript。在與文件輸入相同的形式中,還包括生成的記錄標識。

<form id="main-form" enctype="multipart/form-data"> 
    <input type="hidden" name="recordid" value="123"> 
    <input type="text" name="title"> 

    .... etc fields 
</form> 
<form id="file-form" enctype="multipart/form-data" target="file_frame"> 
    <div id="placeholder-box">Select a file</div> 
    <input type="file" multiple name="record_attachments"> 
    <input type="hidden" name="recordid" value="123"> 
</form> 

之後,你有兩種形式,您可以使用JavaScript文件形式提交給價值變動後的iframe,防止頁面重新加載提交。

<iframe name="file_frame" id="file_frame" src="path_to_upload_script" /> 

一些示例的javascript:More in-depth script here

$("input.[name=record_attachments]").change(function() { 
    $("#file_form').submit(); 
}); 

因爲你包括隱伏recordid場,你可以在用戶完成其他部分之後使用此兩種形式的關聯。

+0

請注意,我沒有太多關於ruby-specifics的信息,但這是客戶端部分應該如何工作的。實際的上傳腳本我不會幫助,但希望這可以指導您正確的方向。 – shamsup

+0

感謝ShamSUP!在頁面加載中將記錄ID分配給記錄是否是線程安全的?此外,惡意用戶是否能夠使用類似Chrome開發工具的方式來編輯隱藏字段中的recordid,從而使RecordAttachments指向錯誤的Record ID?想到我可以保存RecordAttachments,將他們返回的ID傳遞給當前用戶的會話散列,然後在記錄表單完成時,更新用戶剛剛上傳的每個RecordAttachment的record_id字段,是否瘋了? – duhaime

+0

會話變量肯定會走,我完全由於某種原因而使用它。 – shamsup

相關問題