模型无关 Rails 4 动态加载(嵌套)表单域中的文件上传

Model-independent Rails 4 file upload in dynamically loaded (nested) form field

我正在寻找一种将图像简单上传到文件系统的方法,这样图像就不会存储在数据库中。我知道这一步相当简单,只需使用 file_input 标记,但是由于我的表单构建方式,我在实现它时遇到了问题。

我有一个项目,我通过让用户为页面指定页面布局或模板来创建静态活动页面。一旦用户 select 确定了他们要为其页面加载的模板,就会加载一个表单,其中包含指定模板包含的每个小部件的部分。用户输入他们的信息,按下提交,然后创建一个静态页面。

其中一个小部件是图像小部件,用户应该从他们的系统中 select 一个文件,该文件应该在提交表单时上传到服务器。问题是,由于我使用表单助手的方式,我面临着这样的问题,文件上传将文件名作为字符串而不是 IO 对象 (https://www.ruby-forum.com/topic/125637)。我需要帮助来解决这个问题。

用于将数据输入页面的表单(存储在 table campaign_pages 中)如下所示:

= form_for(@campaign_page, class: 'form-horizontal') do |f|
  fieldset
    legend Basic page information
    .form-group
      = f.label :featured, class: 'control-label col-lg-2'
      .col-lg-10
        = f.check_box :featured, class: 'form-control'

      = f.label :title, class: 'control-label col-lg-2'
      .col-lg-10
        = f.text_field :title, placeholder: 'Unique and really catchy page title!', class: 'form-control'

      = f.label :campaign_id, 'Campaign: ', class: 'control-label col-lg-2'
      .col-lg-10
        = f.select :campaign_id, options_from_collection_for_select(@campaigns, 'id', 'campaign_name', @campaign), {}, html_options= {:class => 'form-control'}

      = f.label :language_id, 'Language: ', class: 'control-label col-lg-2'
  .col-lg-10
        = f.select :language_id, options_from_collection_for_select(Language.all,'id', 'language_name'), {}, html_options= {:class => 'form-control'}

      label for='template_id' class='control-label col-lg-2' Template: 
  .col-lg-10
        = select_tag 'template_id', options_from_collection_for_select(@templates, 'id', 'template_name', @template), class: 'form-control'
      | data-no-turbolink="true"

这是在 selected 模板后加载页面上每个小部件的内容表单的地方:

    #widget_location
      = render :file => 'templates/show_form', layout: false

    .form-group
      = f.submit 'Save Page', class: 'btn btn-sm btn-primary'

图像小部件的表单(产生问题)如下所示:

#image_widget_form.form-group
  = label_tag 'widgets[image][image_url]', 'Image URL:', class: 'control-label col-lg-2'
  .col-lg-10
    = text_field_tag 'widgets[image][image_url]', options['image_url'], class: 'form-control'
    = hidden_field_tag 'widgets[image][widget_type]', WidgetType.find_by(:widget_name => 'image').id
    = file_field_tag 'widgets[image][image_upload]'

阅读文档 (http://guides.rubyonrails.org/form_helpers.html#uploading-files) 和其他问题报告后,我的理解是问题出在 "multipart => true",如果您希望文件字段标签起作用,则必须指定它。这应该不是问题,因为我使用的是 form_for @campaign_page 而不是 form_tag。但是,小部件及其内容不属于活动页面 table,因此它们未在活动页面的模型中指定。因此,我不能简单地使用 f.file_field 作为文件输入。

我正在为此寻找解决方案。使用嵌套属性然后使用 field_for 进行图片上传是否可行?

另一个问题是小部件的规范和内容存储在 Postgres JSONB 字段中,我不确定嵌套属性如何适用于这些小部件。

我假设表单设置了多部分,因为根据 Rails 文档,没有必要为 form_for 助手指定 multipart => true。然而,修复结果非常简单 - 在表单标签的 html 选项散列中设置 multipart: true 后它起作用:

= form_for(@campaign_page, class: 'form-horizontal', html: {multipart: true}) do |f|
...