【问题标题】:ruby on rails - s3_direct_upload not reactruby on rails - s3_direct_upload 没有反应
【发布时间】:2014-09-07 13:17:54
【问题描述】:

我对 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”、“回形针”

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

我尝试过各种事情,例如搜索启用 javascripts 或编写应始终显示的警报消息,但一切都没有结果。我做的最后一件事是使用回形针 + s3_direct_upload 创建简单的应用程序......出现了栏并且应用程序正在尝试上传到 s3。现在我累了。应用程序肯定有问题。或 ActiveAdmin。明天试试。

【问题讨论】:

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


    【解决方案1】:

    是我的疏忽搞砸了一切。首先它在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 中,并将 ("#s3_uploader") 中的下划线替换为连字符:

    <%= 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 模型中的方法 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
    

    另外我应该提一下severe_c0der 建议的补丁。谢谢。

    而且,作为神化,我在 active_admin.css.scss 中添加了这个字符串,使进度条可见:

    @import "s3_direct_upload_progress_bars";
    

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

    【讨论】:

      【解决方案2】:

      我也遇到了s3_direct_upload gem 的问题,我的问题与您的问题相似,并且该问题与 S3 存储桶的 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 中注释掉补丁,否则可能是您的存储桶或 AWS 凭证有问题。

      6. 重启你的 Rails 服务器

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

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

      【讨论】:

      • 我以为我已经有了这个示例应用程序,但是......我有这个:github.com/uberllama/s3_direct_upload_example 有趣的是,起初这个应用程序说上传失败,但我添加了提到的补丁并且应用程序开始了去工作。尽管如此,我还是为我的应用程序应用了补丁,但似乎代码中的其他地方出现了问题,因为当我选择要上传的文件时,在控制台中甚至没有提及它。我将检查示例代码,看看是否能找到一些东西。
      【解决方案3】:

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

      【讨论】:

      • 哇,谢谢你的回复,瓦伦。我使用该配置添加了更新。
      • 仍然无法正常工作,顺便说一句 :) 我之前曾尝试将我的 _form.html.erb 从 activeadmin 中移出,但没有显示栏或上传的迹象。
      猜你喜欢
      • 1970-01-01
      • 2011-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多