Carrierwave、Rails 4和多文件上传

13
我一直在尝试让Carrierwave、Rails 4和Multiple Uploads协同工作,但却一直碰壁。我可以像其他项目一样成功地上传单个文件。这不是嵌套的情况——只是简单地上传到一个名为Transcription的单个模型,并希望为每个上传的文档创建一条记录。 我似乎找不到正确的声明用于Carrierwave挂载的“document”字段的方式。
mount_uploader :document, DocumentUploader

作为强参数识别的数组。

我尝试了白名单:whitelisted[:document] = params[:transcription]['document']

将“document”声明为一个数组:

params.require(:transcription).permit(..... ,:document => [])

params.require(:transcription).permit(..... , { document: [] })

这似乎更像是我在声明一个嵌套模型的数组,但是我真正想要的是让Rails 4的strong parameters仅查看由file_field创建的“document”数组,:multiple => true

即。来自日志:form-data; name=\"transcription[document][]

有人成功地在Rails 4中使用strong parameters进行多个上传吗?如果是,请分享一下。

谢谢...

干杯,

比尔

4个回答

36

以下是从零开始使用carrierwave在Rails 4中上传多张图片的解决方案:

只需按照以下步骤操作即可。

rails new multiple_image_upload_carrierwave

在 gem 文件中

gem 'carrierwave'
bundle install
rails generate uploader Avatar 

创建文章脚手架

rails g scaffold post title:string

创建 post_attachment 脚手架

rails g scaffold post_attachment post_id:integer avatar:string

rake db:migrate

在 post.rb 文件中

class Post < ActiveRecord::Base
   has_many :post_attachments
   accepts_nested_attributes_for :post_attachments
end

在 post_attachment.rb 文件中

class PostAttachment < ActiveRecord::Base
   mount_uploader :avatar, AvatarUploader
   belongs_to :post
end

在post_controller.rb文件中

def show
   @post_attachments = @post.post_attachments.all
end

def new
   @post = Post.new
   @post_attachment = @post.post_attachments.build
end

def create
   @post = Post.new(post_params)

   respond_to do |format|
     if @post.save
       params[:post_attachments]['avatar'].each do |a|
          @post_attachment = @post.post_attachments.create!(:avatar => a, :post_id => @post.id)
       end
       format.html { redirect_to @post, notice: 'Post was successfully created.' }
     else
       format.html { render action: 'new' }
     end
   end
 end

 def update
   respond_to do |format|
     if @post.update(post_params)
       params[:post_attachments]['avatar'].each do |a|
         @post_attachment = @post.post_attachments.create!(:avatar => a, :post_id => @post.id)
       end
     end
  end

  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to @post }
      format.json { head :no_content }
    end
  end


 private
   def post_params
      params.require(:post).permit(:title, post_attachments_attributes: [:id, :post_id, :avatar])
   end

在视图/views/posts/_form.html.erb中

<%= form_for(@post, :html => { :multipart => true }) do |f| %>
   <div class="field">
     <%= f.label :title %><br>
     <%= f.text_field :title %>
   </div>

   <%= f.fields_for :post_attachments do |p| %>
     <div class="field">
       <%= p.label :avatar %><br>
       <%= p.file_field :avatar, :multiple => true, name: "post_attachments[avatar][]" %>
     </div>
   <% end %>

   <% if params[:controller] == "post" && params[:action] == "edit" %> 
     <% @post.post_attachments.each do |p| %>
       <%= image_tag p.avatar, :size => "150x150" %>
     <% end %>
   <% end %>

   <div class="actions">
     <%= f.submit %>
   </div>
<% end %>

在views/posts/show.html.erb中

<p id="notice"><%= notice %></p>

<p>
  <strong>Title:</strong>
  <%= @post.title %>
</p>

<% @post_attachments.each do |p| %>
  <%= image_tag p.avatar_url, :size => "150x150" %>
  <%= link_to "Destroy", p, method: :delete %>
<% end %>

<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>
在Rails 3中,不需要定义 strong parameters。你可以在模型和接受嵌套属性的模型中定义 attribute_accessible,因为在Rails 4中,attribute accessible已经被弃用。

很棒的帖子@SSR,这是我唯一成功实现的多文件上传。不知道你是否能稍微扩展一下?在当前形式下,当父模型被删除时,文件并没有被删除(或者对我来说没有),我想知道如何同时编辑帖子及其附件。 - Darkstarone
我想知道post_controller.rb应该怎么样才能正确地编辑和删除附件? - Darkstarone
2
@Darkstarone:谢谢夸奖。:) 我已经更新了我的答案以供编辑方法使用。 - SSR
2
更新了我的答案,加入了destroy方法。 - SSR
使用Ruby文件读取/写入/删除方法从上传文件夹中删除文件。 - SSR
显示剩余3条评论

0
我会创建一个名为“文档”的模型,并在其中添加一个已挂载的字段。
class Documents < ActiveRecord::Base
  belongs_to :transcription

  mount_uploader :doc, DocumentUploader
end

class Transcriptions < ActiveRecord::Base
  has_many :documents
end

而且我仍然会在我的控制器中使用以下行:

params.require(:transcription).permit(..... , { document: [] })

0

0
CarrierWave不支持多个上传。它的设计是将一个文件与一个字段关联起来。
如果你需要多个上传,你需要使用多个字段(每个都有一个CarrierWave uploader),或者多个对象,每个对象只有一个CarrierWave uploader字段。 multiple属性也不支持,因此如果你使用它,完全取决于你正确分配参数。

2
这不是真的。它支持单个字段内的多个上传。请看我的答案。CarrierWave提供更多功能。 - SSR
1
只是为了明确:您的解决方案使用多个对象(post_attachments),每个对象都有一个单独的上传者,并演示了手动工作所必需的参数分配,以便使用“multiple”属性。您已经演示了如何做到OP想要的,但这并不使上述任何部分变得错误。 - Taavo
时间持续向前推进。地球转动并逐渐变化,而CarrierWave现在支持原生多文件上传。然而,CarrierWave的做法是一种丑陋的黑客方式(使用数组引用一个字段中的所有文件),我会避免使用它。最好选择SSR的解决方案。 - Toby 1 Kenobi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接