我希望使用新的Rails 5.2 ActiveStorage功能将文件上传文件添加到Card模型(包括单个文件和多个文件)。我在Rails中更强大,并且正在使用Vue.js来实现这一目标-以前,我将使用Paperclip来处理此问题。但是,我已经设置了config/storage.yml
文件和ActiveStorage的必要迁移。我还设置了卡片上的关联,并更新了CardController
以允许files: []
。
我目前创建的card.vue
组件运行良好;卡可以具有标题和描述,并且描述可以更新。这些记录将保留到数据库中。我的问题是弄清楚如何将文件上传绑定到卡上,以及在保存时上传多个文件所需的逻辑。
当前,我正在使用<input name="files" type="file" data-direct-upload-url="/rails/active_storage/direct_uploads" direct_upload="true" />
在卡中创建输入字段。但是,从本地计算机上选择PDF图像并单击“保存”后,日志显示没有任何反应[关于在active_storage_attachments中插入新行或创建Blob]。如何扩展save方法来接受文件?
card.rb
class Card < ApplicationRecord
has_many_attached :files
end
CardController
class CardsController < ApplicationController
private
def card_params
params.require(:card).permit(:list_id, :title, :position, :description, files: [])
end
end
card.vue
<template>
<div>
<div @click="editing=true" class="card card-body">
<h4>
{{card.title}}
</h4>
</div>
<div v-if="editing" class="modal-backdrop show"></div>
<div v-if="editing" @click="closeModal" class="modal show" style="display: block">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div>
<h4>
{{card.title}}
</h4>
</div>
</div>
<div class="modal-body">
<div>
<h5>{{card.description}}</h5>
</div>
<textarea v-model="description" class="form-control"></textarea>
</div>
<div class="modal-footer">
<input name="files" type="file" data-direct-upload-url="/rails/active_storage/direct_uploads" direct_upload="true" />
<button @click="save" type="button" class="button button-secondary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["card", "list"],
data: function() {
return {
editing: false,
title: this.card.title,
description: this.card.description,
files: []
}
},
methods: {
save: function() {
var data = new FormData
data.append("card[title]", this.title)
data.append("card[description]", this.description)
Rails.ajax({
url: `/cards/${this.card.id}`,
type: "PATCH",
data: data,
dataType: "json",
success: (data) => {
const list_index = window.store.lists.findIndex((item) => item.id == this.list.id)
const card_index = window.store.lists[list_index].cards.findIndex((item) => item.id == this.card.id)
window.store.lists[list_index].cards.splice(card_index, 1, data)
this.editing = false
}
})
}
}
}
</script>
答案 0 :(得分:3)
尝试更改您的输入名称以适合您允许的参数:
<input name="card[files][]" type="file" ... />
已更新:
正如我回答的那样,您需要更改参数以适合允许的参数。
现在,使用Vue,您可以删除name
并将文件添加到ChangeData上的FormData中,如下所示:
<template>
<div>
...
<div class="modal-footer">
<input ref="files" type="file" @change="onFilesChange"
data-direct-upload-url="/rails/active_storage/direct_uploads"
direct_upload="true" multiple />
<button @click="save" type="button" class="button button-secondary">Save changes</button>
</div>
...
</div>
</template>
<script>
export default {
props: ["card", "list"],
data: function() {
return {
editing: false,
title: this.card.title,
description: this.card.description,
form: new FormData
}
},
methods: {
onFilesChange: function() {
let files = this.$refs.files.files
for(let file of files) {
this.form.append('card[files][]', file)
}
},
save: function() {
this.form.append("card[title]", this.title)
this.form.append("card[description]", this.description)
Rails.ajax({
url: `/cards/${this.card.id}`,
type: "PATCH",
data: this.form,
dataType: "json",
success: (data) => {
// ...
this.editing = false
}
})
}
}
}
</script>
注意:如果要上传多个文件,请不要忘记输入的multiple
属性。
答案 1 :(得分:0)
我倾向于这样做:
let input_file = document.querySelectorAll('input[type="file"]')
// ...
formData.append('card[files]', input_file.files[0]) // or loop through if need be, also it might be card[files][0], I can't remember
不确定是否需要多个文件或仅一个文件。而且,前提是您不想像您的代码所建议的那样以异步方式提交它。