【问题标题】:multiple image uploads in a nested form with carrierwave使用carrierwave以嵌套形式上传多个图像
【发布时间】:2013-03-14 00:53:54
【问题描述】:

我正在关注railscasts episode 381,试图允许使用carrierwave gem 和jQuery 文件上传将多个图像上传到我的应用程序。

我的应用程序用于一个大学项目,并设置了一个 hikingtrails 模型,该模型具有许多并接受 pics 模型的嵌套属性。

在我将 file_field 的 multiple 选项设置为 true 并硬编码输入名称属性(即 <%= form.file_field :image, multiple: true, name: "pic[image]" %>)后,carrierwave 停止工作,它不会像以前那样上传单个文件。

这可能与使用嵌套表单有关吗?我也尝试在我的应用中实现这个tutorial,但没有成功。

我也尝试过将这两种表单制作成多部分,而不仅仅是父表单并删除我正在使用的 simple_form gem。

我也尝试过移除部分表单并将嵌套表单放入本地,但这并没有帮助。也许这与我如何将 file_field 设置为多个有关,因为这是问题开始的地方。

任何建议或替代方法将不胜感激

型号

class Pic < ActiveRecord::Base
  belongs_to :hikingtrail

  attr_accessible :img_name, :image, :remote_image_url

  mount_uploader :image, ImageUploader
end

&

class Hikingtrail < ActiveRecord::Base
  attr_accessible :description, 
                                  :duration_hours, 
                                  :duration_mins, 
                                  :meta_description, 
                                  :name, 
                                  :looped,
                                  :pics_attributes

    validates :name,  :presence => true

    has_many :pics

    accepts_nested_attributes_for :pics, :allow_destroy => :true,
    :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end

观看次数

hikingtrails/_form.html.erb

<% @hikingtrail.pics.build %>
<%= simple_form_for @hikingtrail, :html => {:multipart => true}  do |f| %>

<%= f.input :name %>    

<%= f.input :description, :input_html => { :cols => 10, :rows => 3 } %>

<%= f.input :looped %>


  <h2>Images</h2>
  <%= render :partial => 'pics/form',
             :locals => {:form => f} %>


  <div class="form-actions">
    <%= f.submit nil, :class => 'btn btn-primary' %>
    <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
                hikingtrails_path, :class => 'btn' %>
  </div>
<% end %>

图片/_form.html.erb

<%= form.fields_for :pics do |pic_form| %>
  <div class="field">

    <% unless pic_form.object.nil? || pic_form.object.new_record? %>
    <%= image_tag pic_form.object.image_url(:thumb).to_s %>
    <% end %>

    <% if pic_form.object.nil? || pic_form.object.new_record? %>
    <%= pic_form.file_field :image, multiple: true, name: "pic[image]" %>
    <% end %>

  </div>
  <% unless pic_form.object.nil? || pic_form.object.new_record? %>
    <div class="field">
      <%= pic_form.label :_destroy, 'Remove:' %>
      <%= pic_form.check_box :_destroy %>
    </div>
  <% end %>
<% end %>

终端输出

Started PUT "/hikingtrails/7" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Processing by HikingtrailsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"trGCi0Gz+CNRmwAoktcYmeplEKW5bZBtozkduNIXvcI=", "hikingtrail"=>{"name"=>"Dunran Woods", "meta_description"=>"Nice walk through the woods", "description"=>"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "looped"=>"0", "duration_hours"=>"9", "duration_mins"=>"45"}, "pic"=>{"image"=>#<ActionDispatch::Http::UploadedFile:0x007f288085cc08 @original_filename="spink_sleepers.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"pic[image]\"; filename=\"spink_sleepers.jpg\"\r\nContent-Type: image/jpeg\r\n", @tempfile=#<File:/tmp/RackMultipart20130324-7791-19ma2cb>>}, "commit"=>"Update Hikingtrail", "id"=>"7"}
  Hikingtrail Load (3.7ms)  SELECT "hikingtrails".* FROM "hikingtrails" WHERE "hikingtrails"."id" = $1 LIMIT 1  [["id", "7"]]
   (0.1ms)  BEGIN
   (0.1ms)  COMMIT
Redirected to http://0.0.0.0:3000/hikingtrails/7
Completed 302 Found in 6ms (ActiveRecord: 3.8ms)


Started GET "/hikingtrails/7" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Processing by HikingtrailsController#show as HTML
  Parameters: {"id"=>"7"}
  Hikingtrail Load (3.4ms)  SELECT "hikingtrails".* FROM "hikingtrails" WHERE "hikingtrails"."id" = $1 LIMIT 1  [["id", "7"]]
  Pic Load (0.2ms)  SELECT "pics".* FROM "pics" WHERE "pics"."hikingtrail_id" = 7
  Rendered collection (0.0ms)
  Rendered hikingtrails/show.html.erb within layouts/application (2.6ms)
  Rendered layouts/_navbar.html.erb (0.9ms)
  Rendered layouts/_footer.html.erb (0.3ms)
Completed 200 OK in 41ms (Views: 36.2ms | ActiveRecord: 3.7ms)


Started GET "/assets/application.css?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /application.css - 304 Not Modified (0ms)
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/bootstrap_and_overrides.css?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /bootstrap_and_overrides.css - 304 Not Modified (0ms)
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/jquery-fileupload/vendor/jquery.ui.widget.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /jquery-fileupload/vendor/jquery.ui.widget.js - 304 Not Modified (5ms)


Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /jquery_ujs.js - 304 Not Modified (0ms)


Started GET "/assets/jquery.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /jquery.js - 304 Not Modified (0ms)
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-transition.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /twitter/bootstrap/bootstrap-transition.js - 304 Not Modified (0ms)


Started GET "/assets/jquery-fileupload/jquery.fileupload.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /jquery-fileupload/jquery.fileupload.js - 304 Not Modified (0ms)


Started GET "/assets/jquery-fileupload/jquery.iframe-transport.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /jquery-fileupload/jquery.iframe-transport.js - 304 Not Modified (0ms)


Started GET "/assets/jquery-fileupload/basic.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /jquery-fileupload/basic.js - 304 Not Modified (0ms)
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-modal.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /twitter/bootstrap/bootstrap-modal.js - 304 Not Modified (0ms)
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-alert.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /twitter/bootstrap/bootstrap-alert.js - 304 Not Modified (0ms)
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:17] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-dropdown.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:17 +0000
Served asset /twitter/bootstrap/bootstrap-dropdown.js - 304 Not Modified (8ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-tab.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-tab.js - 304 Not Modified (8ms)


Started GET "/assets/twitter/bootstrap/bootstrap-scrollspy.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-scrollspy.js - 304 Not Modified (3ms)


Started GET "/assets/twitter/bootstrap/bootstrap-popover.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-popover.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-tooltip.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-tooltip.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-button.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-button.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-carousel.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-carousel.js - 304 Not Modified (0ms)


Started GET "/assets/twitter/bootstrap/bootstrap-affix.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-affix.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-collapse.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-collapse.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/twitter/bootstrap/bootstrap-typeahead.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap/bootstrap-typeahead.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/bootstrap.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /bootstrap.js - 304 Not Modified (0ms)


Started GET "/assets/twitter/bootstrap.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /twitter/bootstrap.js - 304 Not Modified (0ms)


Started GET "/assets/pics.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /pics.js - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/static_pages.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /static_pages.js - 304 Not Modified (0ms)


Started GET "/assets/hikingtrails.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /hikingtrails.js - 304 Not Modified (0ms)


Started GET "/assets/application.js?body=1" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /application.js - 304 Not Modified (2ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true


Started GET "/assets/fontawesome-webfont.woff?v=3.0.2" for 127.0.0.1 at 2013-03-24 13:55:18 +0000
Served asset /fontawesome-webfont.woff - 304 Not Modified (0ms)
[2013-03-24 13:55:18] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true

【问题讨论】:

  • 我不确定我是否正确,但嵌套表单是否知道此“图片”将用于从父表单创建的对象?我有类似的东西,但我没有t render an template but create the form in the same template using a form_for tag
  • 感谢马丁,但是当我像这样对表单进行编码时,我得到了远足路径属性的 NoMethodError,也许我的 PicsController 没有设置为你的。我按照RailsOrg guide 构建我的模型和表单,一次上传单个图像时效果很好,并且为父表单中的正确对象创建了图片图像。
  • 在哪一行(复制对应的行)。您可能想尝试使用&lt;%= form_for [:hikingtrail, Pics.new] 之类的东西。我不确定它应该是图片还是图片,但你可以试试。如果你这样做 :hikingtrail 表单是针对一个新的 Hikingtrail 而如果你这样做 @hikingrail 这是一个特定的(即对现有对象的编辑)。我认为这是你的问题。

标签: ruby-on-rails ruby-on-rails-3 carrierwave nested-forms railscasts


【解决方案1】:

我花了很长时间尝试实现类似的东西。也许我对这篇文章的回答可能会对你有所帮助。

Rails 3 + JQuery-File-Upload + Nested Model

【讨论】:

    【解决方案2】:

    我从未找到使用 jQuery 文件上传以嵌套形式上传多个图像的解决方案。经过我所做的所有研究,我认为这是不可能的。

    最后我关注了railscast #196,并能够使用carrierwave和javascript一次上传多张图片。

    【讨论】: