ruby on rails - s3_direct_upload没有反应

时间:2014-09-07 13:17:55

标签: ruby-on-rails ruby amazon-s3

我对gem s3_direct_upload有困难。毫无疑问,我遵循了这些精彩的教程并没有取得任何成果:

http://www.blitztheory.com/direct-upload-with-s3_direct_upload/

http://blog.littleblimp.com/post/53942611764/direct-uploads-to-s3-with-rails-paperclip-and

宝石:' aws-sdk',' s3_direct_upload',' activeadmin',' paperclip'

Ruby:2.1.2,Rails:4.1.4

似乎脚本无法正常工作,当我放在那里时,某些文件没有出现进度条,在日志中没有请求被发送,即使我看了firefox控制台。那么我应该怎么做才能使这项工作?

以下是我的文件:

# config/schema.rb
ActiveRecord::Schema.define(version: 20140906145459) do
....
  create_table "images", force: true do |t|
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "photo_file_name"
    t.string   "photo_content_type"
    t.integer  "photo_file_size"
    t.datetime "photo_updated_at"
    t.integer  "gallery_id"
    t.string   "title"
    t.string   "photo_file_path"
    t.string   "direct_upload_url"
  end
end

# app/models/image.rb
class Image < ActiveRecord::Base
    belongs_to :gallery
  acts_as_taggable

    has_attached_file :photo, 
                    :styles => { :small => '300x300>', :medium => '800x800>' }, 
                    :default_url => "images/:style/missing.png"
    validates_attachment_content_type :photo, :content_type => /\Aimage\/.*\Z/

  def self.copy_and_delete(paperclip_file_path, raw_source)
    s3 = AWS::S3.new #create new s3 object
    destination = s3.buckets[Rails.configuration.aws['bucket']].objects[paperclip_file_path]
    sub_source = CGI.unescape(raw_source)
    sub_source.slice!(0) # the attached_file_file_path ends up adding an extra "/" in the beginning. We've removed this.
    source = s3.buckets[Rails.configuration.aws['bucket']].objects["#{sub_source}"]
    source.copy_to(destination) #copy_to is a method originating from the aws-sdk gem.
    source.delete #delete temp file.
  end
end

# app/admin/image.rb
ActiveAdmin.register Image do
  form partial: "form"

  controller do
    def create
      if (params[:image][:attached_file_path])
        @image = Image.new(image_params)
        @gallery = Gallery.find(1)
        @gallery.images << @image

        respond_to do |format|
          if @image.save!
            paperclip_file_path = "images/photo/#{id_partition @image.id}/original/#{params[:image][:photo_file_name]}"
            raw_source = params[:image][:photo_file_path]

            Image.copy_and_delete paperclip_file_path, raw_source
            format.html { redirect_to admin_image_path(@image), notice: 'Image was successfully created.' }
            format.json { render :index, status: :created, location: @gallery }
          else
            format.html { render :new }
            format.json { render json: @article.errors, status: :unprocessable_entity }
          end
        end
      else
        @image = Image.new
        render action: 'new', notice: "No file"
      end
    end
  end
end

# app/views/admin/images/_form.html.erb
<%= s3_uploader_form callback_url: admin_images_url, 
                     callback_param: "image[direct_upload_url]", 
                     id: "s3-uploader" do %>
  <%= file_field_tag :file, multiple: false %>
<% end %>

<div id="uploads_container"></div>
<script id="template-upload" type="text/x-tmpl">
  <div id="file-{%=o.unique_id%}" class="upload">
    {%= o.name %}
    <div class="progress"><div class="bar" style="width: 0%"></div></div>
  </div>
</script>
<br />

<%= semantic_form_for [:admin, @image] do |f| %>  
  <%if @image.errors.any? %>
    <ul>
      <% @image.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  <% end %>

  <%= f.inputs do %>
    <%= f.input :title %>
    <%= f.input :tag_list, hint: "Указывайте теги через запятую" %>
    <%= f.hidden_field :direct_upload_url %>

    <%= f.hidden_field :photo_file_name %>
    <%= f.hidden_field :photo_file_size %>
    <%= f.hidden_field :photo_content_type %>

    <%= f.hidden_field :photo_file_path %>
  <% end %>
  <%= f.actions %>
<% end %>

# config/initializers/active_admin.rb
ActiveAdmin.setup do |config|
  config.register_javascript 's3_direct_upload.js'
  config.register_javascript 'direct_upload.js'
end

# app/assets/javascripts/direct_upload.js.coffee
jQuery ->
  $("#s3_uploader").S3Uploader
    remove_completed_progress_bar: false
    remove_failed_progress_bar: true
    progress_bar_target: $("#uploads_container")
    allow_multiple_files: false
  $("#s3_uploader").bind "s3_uploads_start", (e) ->
    alert("Upload started")
  $("#s3_uploader").bind "s3_upload_failed", (e, content) ->
    alert content.filename + " failed to upload."

  $("#s3_uploader").bind "s3_upload_complete", (e, content) ->
    alert "Upload complete."
    $("#image_direct_upload_url").val(content.url);
    $("#image_photo_file_name").val(content.filename);
    $("#image_photo_file_path").val(content.filepath);
    $("#image_photo_file_size").val(content.filesize);
    $("#image_photo_file_type").val(content.filetype);
  $('#s3_uploader').bind "ajax:success", (e, data) ->
    alert("server was notified of new file on S3; responded with '#{data}")

# config/initializers/aws.rb
require 'aws-sdk'

Rails.configuration.aws = 
  YAML.load(ERB.new(
      File.read("#{Rails.root}/config/amazon_aws.yml")
    ).result)[Rails.env].symbolize_keys!

# config/initializers/paperclip.rb
Paperclip::Attachment.default_options.merge!(
  url: ':s3_domain_url',
  path: '/:class/:attachment/:id_partition/:style/:filename',
  s3_permissions: {
    original: :private
  },
  storage: :s3,
  s3_credentials: Rails.configuration.aws  #config/initializers/aws.rb
)

# config/initializers/s3_direct_upload.rb
S3DirectUpload.config do |c|
  c.access_key_id = Rails.configuration.aws[:access_key_id]
  c.secret_access_key = Rails.configuration.aws[:secret_access_key]
  c.bucket = Rails.configuration.aws[:bucket]
  c.region = nil
  c.url = nil
end

# config/amazon_aws.yml
defaults: &defaults
  access_key_id: "..."
  secret_access_key: "..."
development:
  <<: *defaults
  bucket: "..."
test:
  <<: *defaults
  bucket: "..."
production:
  access_key_id: <%= ENV["ACCESS_KEY_ID"]%>
  secret_access_key: <%= ENV["SECRET_ACCESS_KEY"] %>
  bucket: <%= ENV["S3_BUCKET_NAME"] %>

提前致谢。

更新

CORS配置:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

更新2

我试图做各种各样的事情,比如googing on enable javascripts或写下应该总是显示的警告信息,但是一切都没有结果。我做的最后一件事是使用paperclip + s3_direct_upload创建简单的应用程序...出现了条形图,应用程序试图上传到s3。现在我累了。绝对是app的错误。或者ActiveAdmin。明天会尝试。

3 个答案:

答案 0 :(得分:2)

这是我无意中搞砸了一切。首先是在js文件中:

#= require active_admin/base
#= require s3_direct_upload
jQuery ->
  $("#s3-uploader").S3Uploader
    remove_completed_progress_bar: false
    progress_bar_target: $("#uploads_container")
    allow_multiple_files: false

  $("#s3-uploader").bind "s3_upload_complete", (e, content) ->
    alert "Upload complete."
    $("#image_direct_upload_url").val content.url
    $("#image_photo_file_name").val content.filename
    $("#image_photo_file_path").val content.filepath
    $("#image_photo_file_size").val content.filesize

我将与s3Uploader相关的代码放在activeadmin.js.coffee中,并用(和#34;#s3_uploader&#34;)中的下划线替换了我的表单中的连字符:

<%= s3_uploader_form callback_url: admin_images_url, callback_param: "direct_upload_url", id: "s3-uploader" do %>
  <%= file_field_tag :file, multiple: false %>
<% end %>

另请注意,在callback_url中我使用了admin_images_url,因为它的控制器应该处理这个问题。

但那并不是每次都有效......在测试应用程序中一切都很好,但不是在我的主应用程序中。问题发生在amazon_aws.yml。我删除了access_key_id和secret_access_key周围错误放置的引号,并发送了POST请求。

但是,由于控制器,图像无法正常保存。使用activeadmin我这样做了:

ActiveAdmin.register Image do
  permit_params :title, :tag_list, :direct_upload_url, :photo_file_name, :photo_file_size, :photo_content_type, :photo_file_path

  form partial: "form"

  controller do
    def create
      if params[:url]
        @image = Image.new
        render "new" and return
      end

      if (params[:image][:photo_file_path])
        @image = Image.new(permitted_params[:image])
        @gallery = Gallery.find(1)
        @gallery.images << @image

        respond_to do |format|
          if @image.save!
            paperclip_file_path = "images/photos/#{Paperclip::Interpolations.id_partition( @image.photo, "photo" )}/original/#{params[:image][:photo_file_name]}"
            raw_source = params[:image][:photo_file_path]

            Image.copy_delete_preprocess_save paperclip_file_path, raw_source, @image.id
            format.html { redirect_to admin_image_path(@image), notice: 'Image was successfully created.' }
            format.json { render :index, status: :created, location: @gallery }
          else
            format.html { render :new }
            format.json { render json: @article.errors, status: :unprocessable_entity }
          end
        end
      else
        @image = Image.new
        render action: 'new', notice: "No file"
      end
    end
  end
end

然后我在Image model中更改了方法copy_delete_preprocess_save:

def self.copy_delete_preprocess_save(paperclip_file_path, raw_source, id)
  s3 = AWS::S3.new #create new s3 object
  destination = s3.buckets[Rails.configuration.aws[:bucket]].objects[paperclip_file_path]
  sub_source = CGI.unescape(raw_source)
  sub_source.slice!(0) # the attached_file_file_path ends up adding an extra "/" in the beginning. We've removed this.
  source = s3.buckets[Rails.configuration.aws[:bucket]].objects["#{sub_source}"]

  obj = source.copy_to(destination) #copy_to is a method originating from the aws-sdk gem and store returned object for preprocessing.
  source.delete #delete temp file.

  image = Image.find(id)
  image.photo = obj.url_for(:get)
  image.photo_file_path = nil
  image.save!
end

另外我应该提到serious_c0der建议的补丁。谢谢。

而且,作为一种神化,我在active_admin.css.scss中添加了这个字符串,可以看到进度条:

@import "s3_direct_upload_progress_bars";

感谢您的帮助。希望它可以帮助别人。

答案 1 :(得分:1)

我也遇到了s3_direct_upload gem的问题,我的问题与你的问题类似,问题与S3 Buckets的URL模式有关。这是我的步骤的回顾,帮助我解决了我的问题。

要进行调试,请按以下步骤操作:

  1. 克隆此回购:s3_direct_upload_example

  2. 创建新的测试存储区并设置以下CORS配置:

    <CORSConfiguration>
      <CORSRule>
          <AllowedOrigin>*</AllowedOrigin>
          <AllowedMethod>GET</AllowedMethod>
          <AllowedMethod>POST</AllowedMethod>
          <AllowedMethod>PUT</AllowedMethod>
          <MaxAgeSeconds>3000</MaxAgeSeconds>
          <AllowedHeader>*</AllowedHeader>
      </CORSRule>
    </CORSConfiguration>
    
  3. 将您的AWS凭据导出到环境:

    $ export AWS_S3_BUCKET=your-bucket-name
    $ export AWS_ACCESS_KEY_ID=your-aws-access-key-id
    $ export AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key
    
  4. bundle,运行rails s并转到http://0.0.0.0:3000查看上传是否有效。

  5. 如果上传 正在运行,请在s3_direct_upload.rb中注释掉该补丁,否则可能是您的Bucket或AWS凭据存在问题。< / p>

  6. 重新启动rails服务器

    • 如果上传停止工作 ,您还需要将 Monkey Patch 应用到您的应用中,问题出在宝石无法形成正确的网址。

    • 如果上传仍然有效 ,则问题在于应用中的代码。

答案 2 :(得分:0)

我是那个写过你所链接的第一个教程的人。我会尽力帮助你完成这件事。在direct_upload.js.coffee中,理想情况下,您的错误消息应该触发,并让您知道如果您的CORS设置正确,会发生什么。我怀疑您没有正确设置S3存储桶上的Cross Origin(CORS)设置。请完成该步骤,因为我认为S3从一开始就拒绝了您的请求。