2016-04-28 10 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がnilであるRecordAttachmentsがあるかどうかを確認します。その場合は削除してください。次に、ユーザーが1つまたは複数のファイルを選択します。それぞれに対して、record_idをnilに設定してRecordAttachmentテーブルに行を保存します。次に、ユーザーがレコードフォームを正常に送信した場合は、record_id == nilのユーザーのRecordAttachmentsをすべて検索し、それぞれのrecord_idを現在のレコードのIDに設定します。

これは妥当な解決策のようですか?より良い/簡単な方法がありますか?私は他の人がこの質問に提供できる助けに非常に感謝しています!

答えて

0

このタスクでは、Angular.js用のすばらしいファイルアップロードライブラリng-file-uploadを使用しました。 full sourceは、親レコードを保存する前に子供を保存する必要がある人がいる場合に利用できますが、Javascriptから子供にdbを書き込んで、親を保存したらparent_id要素を更新してください各子供の

0

Javascriptは、ファイル入力フィールドのファイルの内容を実際に読み取ることができないため、残念ながらフォームの残りの部分を入力しようとしている間は、ajax経由で送信できません。それはあなたがラウンドアバウトの方法をいくつか実行することができないことを意味しません。

フォームページが読み込まれたときにレコードIDを生成し、そのIDをメインフォームの非表示の入力に含めて、ファイル入力を別のフォームに入れたり、別のフォームに移動したりすることもできますページの読み込み後にjavascriptでファイル入力と同じ形式で、生成されたレコードIDも含めます。

<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> 

次の2つのフォームを持っていたら、ページが提出でリロード防止、値が変更されたIFRAMEにファイル・フォームを送信するためにJavaScriptを使用することができます。

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

いくつかの例のjavascript:あなたはヒデrecordidフィールドを含めているので、ユーザは、他の部分を完了した後にMore in-depth script here

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

、次の2つのフォームを関連付けるためにこれを使用することができます。

+0

ルビーの詳細についてはあまり情報がありませんが、これはクライアントの部分がどのように動作するかです。実際のアップロードスクリプト私は助けにはなりませんが、うまくいけば、これは正しい方向にあなたを指しています。 – shamsup

+0

ありがとうShamSUP! pageloadのレコードにレコードIDを割り当てるのはスレッドセーフですか?また、悪意のあるユーザーは、隠しフィールドのrecordidをChrome devtoolsなどで編集できないため、RecordAttachmentsが間違ったレコードIDを指していますか? RecordAttachmentsを保存し、返されたIDを現在のユーザーのセッションハッシュに渡し、レコードフォームの完了時に、ユーザーがアップロードした各RecordAttachmentのrecord_idフィールドを更新することは夢中ですか? – duhaime

+0

セッション変数は間違いなく私が何らかの理由でそれを完全に隔てる方法です。 – shamsup

関連する問題