我遇到了将多个文件上传到AWS的问题。我有两种型号Lessons&&附件。课程has_many :attachments
我正在设置一个包含课程字段的表单,我想将多个附件上传到该课程。所有内容都正确上传,除非我上传多个文件,它会创建一个新的课程和附件。我正在努力:
https://gorails.com/episodes/multiple-file-uploads-with-shrine?autoplay=1
和
class Lesson < ApplicationRecord
belongs_to :user
has_many :attachments, dependent: :destroy
accepts_nested_attributes_for :attachments
end
class Attachment < ApplicationRecord
belongs_to :lesson, optional: true
include AttachmentUploader::Attachment.new(:media)
end
Class LessonsController < ApplicationController
# truncated for brevity.
def new
@lesson = current_user.lessons.build
end
def create
@lesson = current_user.lessons.build(lesson_params)
respond_to do |format|
if @lesson.save
if params[:media]
params[:media].each { |media|
@lesson.attachments.create(media_data: media)
}
end
format.html { redirect_to @lesson, notice: 'Lesson was successfully created.' }
format.json { render :show, status: :created, location: @lesson }
else
puts "\n\n\n#{@lesson.errors.full_messages.to_sentence}\n\n\n"
format.html { render :new, notice: @lesson.errors }
end
end
end
private
def set_lesson
@lesson = Lesson.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(
:title,
:content,
:document,
:category_id,
:pinned,
:bootsy_image_gallery_id,
attachments_attributes: {media: []},
)
end
end
class AttachmentsController < ApplicationController
before_action :set_attachment, only: [:edit, :update, :destroy]
def create
@attachment = Attachment.new(attachment_params)
@attachment.save
end
private
def set_attachment
@attachment = Attachment.find(params[:id])
end
def attachment_params
params.fetch(:attachment, {})
end
end
<%= @lesson.errors.full_messages.first if @lesson.errors.any? %>
<%= form_for @lesson do |f| %>
<div class="control-group">
<%= f.label :title %>
<div class="controls">
<%= f.text_field :title, required: true %>
</div>
<div>
<%= f.label :content %>
<%= f.bootsy_area :content, editor_options: { html: false }, rows: "20", cols: "100" %>
</div>
<div>
<%= f.label 'File under at least one class' %>
<%= f.collection_select :category_id, Subject.all, :id, :name, { promt: "Choose a Class" } %>
</div>
<div>
<%= f.label :pinned %>
<%= f.label :pinned, "Yes", value: "Yes" %>
<%= f.radio_button :pinned, true%>
<%= f.label :pinned, "No", value: "No" %>
<%= f.radio_button :pinned, false, checked: true %>
</div>
<hr>
<div>
<%= f.label 'Or Upoad a file' %>
<%
######################
# This is where I have the attachment file field.
######################
%>
<%= file_field_tag "media[]", type: :file, multiple: true %>
</div>
<br>
<%= f.submit nil %>
<%= link_to 'Cancel', lessons_path%>
<div class="form-actions btn-a">
<%= link_to 'Cancel', lessons_path, class: "btn btn-default" %>
</div>
Rails.application.routes.draw do
mount AttachmentUploader::UploadEndpoint => "/attachments/upload"
resources :lessons do
member do
put "like", to: "lessons#upvote"
put "dislike", to: "lessons#downvote"
end
resources :comments
resources :attachments
end
root 'static#index'
end
$(document).on("turbolinks:load", function () {
$("[type=file]").fileupload({
add: function (e, data) {
data.progressBar = $('<div class="progress" style="width: 300px"><div class="progress-bar"></div></dov>').insertAfter("#file-upload");
var options = {
extension: data.files[0].name.match(/(\.\w+)?$/)[0],
_: Date.now() // revent caching
}
$.getJSON("/attachments/upload/cache/presign", options, function (result) {
data.formData = result['fields'];
data.url = result['url'];
data.paramName = "file";
data.submit();
});
},
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
var percentage = progress.toString() + '%';
data.progressBar.find(".progress-bar").css("width", percentage).html(percentage);
},
done: function (e, data) {
console.log("done", data);
data.progressBar.remove();
var document = {
id: data.formData.key.match(/cache\/(.+)/)[1],
storage: 'cache',
metadata: {
size: data.files[0].size,
filename: data.files[0].name.match(/[^\/\\]+$/)[0],
mime_type: data.files[0].type
}
}
form = $(this).closest("form");
form_data = new FormData(form[0]);
form_data.append($(this).attr("name"), JSON.stringify(document))
$.ajax(form.attr("action"), {
contentType: false,
processData: false,
data: form_data,
method: form.attr("method"),
dataType: "json",
success: function(response) {
var $img = $("<img/>", { src: response.image_url, width: 400 });
var $div = $("<div/>").append($img);
$("#photos").append($div);
}
});
}
});
});
答案 0 :(得分:1)
发生这种情况的原因是因为Javascript查找文件字段的父表单的URL。您有创建新课程的表单,这意味着每次上传文件时,它都会创建一个新课程。
要考虑的一些选项是:
将上传表单放在仅在创建课程后才可用的位置。这使您可以创建form_for [@lesson, Attachment.new]
,它将指向正确的URL并让您快速上传文件,但必须首先创建课程。
您可以调整JS不要立即提交AJAX请求,而是使用图像数据附加隐藏字段。
我的截屏视频介绍了这种方法,因为您必须先创建相册才能在相册的显示页面上传。我认为这最终会带来更好的用户体验,因此他们不会担心文件上传失败并导致其他表单数据可能丢失或未保存。