在 Vue.js 中使用 ActiveStorage 上传文件

Veg*_*ios 5 ruby-on-rails vue.js rails-activestorage

我希望使用新的 Rails 5.2 ActiveStorage 功能将文件上传添加到 Card 模型(包括单个和多个文件)。我在 Rails 中更强大,并且正在使用 Vue.js 来解决这个问题 - 以前我会使用 Paperclip 来处理这个问题。但是,我已经config/storage.yml为 ActiveStorage设置了文件和必要的迁移。我还设置了 Card 上的关联并将其更新CardController为 permit 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]。如何扩展保存方法以接受文件?

卡

class Card < ApplicationRecord
  has_many_attached :files
end
Run Code Online (Sandbox Code Playgroud)

卡控制器

class CardsController < ApplicationController
  private
    def card_params
      params.require(:card).permit(:list_id, :title, :position, :description, files: [])
    end
end
Run Code Online (Sandbox Code Playgroud)

卡.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>
Run Code Online (Sandbox Code Playgroud)

Sov*_*ina 7

尝试更改您的输入名称以适合您允许的参数:

<input name="card[files][]" type="file" ... />
Run Code Online (Sandbox Code Playgroud)

更新:

正如我回答的那样,您需要更改参数以适合您允许的参数。
现在使用 Vue,您可以删除name文件并将文件添加到 FormData on change 事件中,如下所示:

<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>
Run Code Online (Sandbox Code Playgroud)

注意:multiple如果要上传多个文件,请不要忘记输入属性。