【问题标题】:Rails Paperclip & Multiple File UploadsRails 回形针和多个文件上传
【发布时间】:2012-06-10 21:37:27
【问题描述】:

我正在寻找一种解决方案,让用户能够通过一个 file_field 上传多个图像。我已经研究过诸如 Jquery File Upload 和 Uploadify 之类的选项,但还没有遇到具有工作解决方案的好例子。

我已经设置了多个图像,

 has_attached_file :asset,
                   :styles => { :large => "640x480", :medium => "300x300", :thumb => "100x100" },
                   :storage => :s3,
                   :s3_credentials => "#{Rails.root}/config/s3.yml",
                   :path => "/:contributor_id/:listing_name/:filename"

现在我正在显示 5 个单独的 file_fields

def new
  @listing = Listing.new
  5.times {@listing.assets.build }

  respond_to do |format|
    format.html # new.html.erb
    format.json { render json: @listing }
  end
end

我想拥有

<%= f.file_field :asset, :multiple => true %>

这允许用户在他们的文件浏览器中选择多个文件。但是如何使用嵌套模型处理这些?并让他们上传。

【问题讨论】:

    标签: ruby-on-rails file-upload amazon-s3 paperclip


    【解决方案1】:

    所以这里有一些问题。

    首先,Paperclip 的has_attached_file 方法与许多文件没有关联。看起来您正在尝试构建一个“资产”,就好像它是一个 Rails 关联一样。 Paperclip 所做的只是将几个字段放入您的表中以存储有关文件的一些元数据,并且每个声明 has_attached_file 都会获得一个附加文件。如果要附加 5 个文件,则需要执行以下操作:

    has_attached_file :asset1
    has_attached_file :asset2
    has_attached_file :asset3
    has_attached_file :asset4
    has_attached_file :asset5
    

    或者,您也可以创建另一个模型来存储文件。例如:

    class Listing < ActiveRecord::Base
      has_many :assets
    end
    
    class Asset < ActiveRecord::Base
      belongs_to :listing
      has_attached_file :picture
    end
    

    这样,您可以将多个资产附加到一个列表中(您没有说明原始对象是什么,所以我将其称为“列表”)。

    其次,在 HTML 中不存在多文件上传(因此,file_field 方法不采用 :multiple =&gt; true 参数。您必须使用 Rails 内置之外的东西如果你想要多文件上传,表单处理。Uploadify 是一个不错的选择(我以前使用过)。有一个 gem 可以转换文件字段以使用 uploadify(并且将支持你想要的 :multiple =&gt; true 语法): https://github.com/mateomurphy/uploadify_rails3/wiki。但是,我不能保证它有多好。

    我的建议是循序渐进。通过 Flash 上传到 Rails 可能是一个复杂的过程,涉及到处理 CSRF 元标记和表单中的其他字段。首先制作一个表单,允许用户上传一个文件并通过 Paperclip 存储它。然后可能将has_attached_file 声明分解为另一个模型,以便您可以拥有一个或多个与模型关联的文件(如上面的多模型代码块所示)。然后尝试添加 Uploadify 或其他替代方法。 Ernie Miller 有一个不错的关于集成 Uploadify 的教程:http://erniemiller.org/2010/07/09/uploadify-and-rails-3/

    首先,请记住has_attached_file 只能附加一个文件。当您尝试致电@listing.assets 时,没有“资产”。有一个资产。如果你想要多个文件,你需要自己创建一个单独的模型并使用 Rails 的关联。

    【讨论】:

    • 我已经创建了另一个名为“Listing”的模型。一个列表 has_many 资产。我已经可以上传多个资产,而不是通过单个“选择文件”字段。如果有人有任何使用uploadify的好例子,那就太好了。我不确定如何做后台 JS 来处理每个图像并将它们正确 POST 到服务器。
    • 您可以将:multiple =&gt; "multiple" 添加到您的file_field,这样就可以从一个html 文件输入字段中选择多个文件(至少在Chrome 中)。我还没有解决正确管理这些上传的问题,但我知道 post 参数包含您选择和上传的多个文件的数组。
    • 您还必须将:html =&gt; {:multipart =&gt; :true } 添加到您的form_for
    • 只是补充一点:我会将文件上传移动到 ajax,允许您从用户那里收集文件列表,然后在后台一次上传一个:这样它会对用户来说,他们一次上传了很多文件,即使幕后情况并非如此。您还可以设置任何其他参数,以了解在服务器上可能需要如何组织结果记录。对于使用 ajax (jquery) 上传文件,这可能有点棘手,请参阅例如 abandon.ie/notebook/simple-file-uploads-using-jquery-ajax
    【解决方案2】:

    接受的答案是 HTML 中不存在多文件上传。

    <%= f.file_field :files, multiple: true %>
    

    这允许您选择多个图像并将它们作为数组发送。

    如果您有Dog has_many ImagesImage has_attachment :file 的关系,请执行此操作以一次上传多张图片:

    在你的 html.erb 中

    <%= form_for @dog, html: { multipart: true } do |f| %>
      <%= f.file_field :files, accept: 'image/png,image/jpeg,image/gif', multiple: true %>
    <%= end %>
    

    在你的控制器中

    def dog_params
      params.require(:dog).permit files: []
    end
    

    在你的狗模型中

    def files=(array = [])
      array.each do |f|
        images.create file: f
      end
    end
    

    这是假设您已经能够上传一张图片但想一次升级到多张图片。请注意等待时间会增加。

    为帮助减少等待时间,请查看我的 post,了解有关速度上传的问题。

    【讨论】:

    • 如果可以的话,我会多次投票。我被困了一整天,第二天早上发现了第一件事。开始新的一天的好方法!
    【解决方案3】:

    这是一个多文件上传的完整示例。这里是user has_many uploads。每个upload 模型都有一个avatar,它代表文件附件。最终:当我们创建 user 时,我们会创建许多 uploads

    模型

    #models/user.rb
    class User < ApplicationRecord
      has_many :uploads
    
      def files=(array_of_files = [])
        array_of_files.each do |f|
          uploads.build(avatar: f, user: self)
        end
      end
    end
    
    
    #models/upload.rb
    class Upload < ApplicationRecord
      belongs_to :user
    
      has_attached_file :avatar
      validates_attachment_content_type :avatar, :content_type => ["image/png"]
    end
    

    形式:

    # views/users/_form.html.erb
    <%= form_with(model: user, local: true) do |form| %>
    
      ...
    
      <div class="field">
        <%= form.file_field :files, multiple: true %>
      </div>
    
      <div class="actions">
        <%= form.submit %>
      </div>
    <% end %>
    

    控制者

    class UsersController < ApplicationController
      before_action :set_user, only: [:show]
    
      def show
      end
    
      def new
        @user = User.new
      end
    
      def create
        @user = User.new(user_params)
    
        if @user.save
          redirect_to @user, notice: 'User was successfully created.'
        end
      end
    
      private
        def set_user
          @user = User.find(params[:id])
        end
    
        def user_params
          params.require(:user).permit(:name, files: [])
        end
    end
    

    用户#show

    <p id="notice"><%= notice %></p>
    
    <p>
      <strong>Name:</strong>
      <%= @user.name %>
    </p>
    
    
    <h3>Uploads</h3>
    <div>
      <% @user.uploads.each do |upload|  %>
        <div>
          <%= link_to upload.avatar.url do%>
            <%= upload.avatar_file_name %>
          <% end %>
        </div>
      <% end %>
    </div>
    
    <%= link_to 'Edit', edit_user_path(@user) %> |
    <%= link_to 'Back', users_path %>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-20
      • 1970-01-01
      • 2018-05-06
      • 1970-01-01
      • 2014-04-14
      相关资源
      最近更新 更多