使用Carrierwave直接上传到S3

7

最近我将以下内容从使用Paperclip转换为使用Carrierwave上传到Amazon S3,以便我可以利用carrierwave_direct宝石和Sidekiq或其他后台处理宝石。

class Release < ActiveRecord::Base
  has_many :releases_tracks, :dependent => :destroy
  has_many :tracks, :through => :releases_tracks, :order => "releases_tracks.position DESC"
  accepts_nested_attributes_for :tracks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => :true
  accepts_nested_attributes_for :releases_tracks  
end

class Track < ActiveRecord::Base
  mount_uploader :track, TrackUploader
  has_many :releases_tracks, :dependent => :destroy
  has_many :releases, :through => :releases_tracks 
end

/views/releases/track_upload.html.erb

<%= form_for(@release, :html => { :multipart => true }) do |f| %>
<h3>Upload Tracks for <%= @release.title %></h3>
    <% index = 0 %>
    <%= f.fields_for :tracks do |builder| %>
    <%= @release.tracks[index].name %>
        <%= f.file_field :track, :class => "file styled", :title => 'Select Track'%>
    <% index += 1 %>
    <% end %>

    <%= f.submit "Upload Tracks", :class => "submit" %>
<% end %>

承载波上传已经可以使用,但我无法弄清如何使直接部分起作用。部分原因是我不知道如何将建议的表单代码合并进去:
<%= direct_upload_form_for @uploader do |f| %>
  <%= f.file_field :track %>
  <%= f.submit %>
<% end %

或者在我的轨道或发布控制器中放置建议的位置:

@uploader = User.new.track
@uploader.success_action_redirect = new_user_url

这篇说明文档https://github.com/dwilkie/carrierwave_direct和Railscasthttp://railscasts.com/episodes/383-uploading-to-amazon-s3都指向先上传文件,然后创建数据库条目。但在我的应用程序中,数据库条目已经存在。Railscast确实说过这是可能的,但没有详细介绍。这是第一个问题。

第二个问题是我需要一次上传多个文件。上面的代码可以实现,但速度非常慢,当然也会使我的应用程序变得无用。

有谁能帮忙吗?提前感谢!

1个回答

20
首先,我建议你不要使用carrierwave_direct,出于很多原因,我真的不喜欢这个gem。 其中一个原因是,正如文档中所说:

请注意,此gem仅支持单个文件上传。如果您想同时上传多个文件,则必须使用JavaScript或Flash上传器。

但如果您想使用它,这是我猜测您需要做的:

首先关于

@uploader = User.new.track
@uploader.success_action_redirect = new_user_url

似乎你正在尝试上传音轨,并且据你所说,你已经创建了模型,我猜你是想为现有的发布上传新的音轨。如果我理解错误,请纠正我。
因此,在ReleasesController#track_upload方法中应该创建@uploader变量。
class ReleasesController
  ...  
  def track_update 
    @uploader = User.new.track
    @uploader.success_action_redirect = new_user_url
  end
  ...
end

然后在相关的视图中 (/views/releases/track_upload.html.erb),您可以使用 direct_upload_form 表单。

<%= direct_upload_form_for @uploader do |f| %>
  <%= f.file_field :track %>
  <%= f.submit %>
<% end %>

在您选择文件后,表格将直接将文件上传到s3。然后我不知道确切的方式,但是carrierwave_direct应该会返回已上传文件的URL。

我对此并不确定,因为我从未深入研究过它,但是想法是您的文件刚刚上传到了s3,现在必须将其链接到您的模型,以便文件不会“丢失”。

所以也许carrierwave_direct是自己处理的(我很怀疑...)通过执行某些ajax请求或其他任何操作。

无论如何,由于您想要上传多个文件,我想向您介绍一个我最近写的教程

这显示了如何直接将文件上传到s3,而不使用carrierwave_direct,而是自行处理。这需要更多的代码和时间,但您可以更好地控制发生的事情。

在您的情况下,您需要将我在教程中使用的表单放在您的视图中,在/views/releases/track_upload.html.erb视图中。 然后,一旦您选择了文件,成功的AJAX请求(由jQueryFileUpload插件发出)将为您提供上传文件的URL,以便您可以将其保存在Track模型中(您可能希望向服务器发出新的AJAX请求来创建新的Track模型,或者填充页面上的其他表单,例如您在/views/releases/track_upload.html.erb文件中使用的表单,然后在提交时保存轨迹。) 如果我表述不清楚,请告诉我是否需要更多解释。
好处是,如果您只需将multiple添加到文件输入中,则很棒的jQueryFileUpload插件将为每个文件发送一个请求到s3,然后您将在每个ajax结果中获得已上传文件的URL。
您可以使用jQuery插件进行调整以添加进度条等内容,您真的可以创建令人惊叹的东西。
希望这会对您有所帮助!

哇,谢谢你提供这么好的答案。我认为你的教程更接近我想要实现的内容,所以我会立刻开始学习。我会反馈我的学习进度的。再次感谢! - Raoot
我完全同意你的第一句话。我再也不会使用carrierwave_direct了。下次需要上传器时,我打算从头开始实现一个,并期望它花费更少的时间并且工作得更好。 - user657199
也许你可以查看这个 gem:https://github.com/waynehoover/s3_direct_upload 它看起来非常有趣 :) - pjam
谢谢。简短易懂的确很好。我越来越怀疑Rails插件过于复杂和模块化的架构。它可以使简单任务变得复杂,而将复杂任务优雅地简化——只要你永远不必干涉任何事情。一旦我确保我们的生产服务器没有丢失更多数据,我就会去看一下。顺便说一下,有很多奇怪的事情发生。S3存储桶名称中的下划线(应该在us-east存储桶下允许)有时会失败...文件名中带有空格似乎无法使用,默认情况下失败,重命名带来了很多麻烦。唉。 - user657199
对于你的 carrierwave_direct 回答,你需要将 success_action_redirect 设置为 POST track_update 操作,该操作将把密钥分配给模型。 - lulalala
显示剩余3条评论

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