• ROR使用attachment_fu上传附件


    ROR使用attachment_fu上传附件,很方便,但是配置需要研究。

    http://github.com/technoweenie/attachment_fu


    migration:

    class CreateAttachments < ActiveRecord::Migration
      def self
    .up
        create_table 
    :attachments,:force => true do |t|
          t
    .string :filename,:default=>""
          t
    .string :content_type,:defaut=>""
          t
    .integer :size,:default=>0
          t
    .string :org_filename,:default=>""

          t
    .timestamps
        end
      end

      def self
    .down
        drop_table 
    :attachments
      end
    end


    model:

    class Attachment < ActiveRecord::Base
      has_attachment :content_type 
    => [:image,'application/pdf''application/msword''text/plain'],
        :max_size 
    => 4.megabytes, #指定最大值
      :storage => :file_system,  #指定存储方式
      :path_prefix => "/public/attachments/#{Time.now.year}/#{Time.now.month}/#{Time.now.day}/"

      validates_as_attachment

    end


    view:

    <form name="upload" action="/attachments/create" method="post" ENCTYPE="multipart/form-data" >
      
    <% if protect_against_forgery? %>
        
    <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" >
      
    <% end %>
      
    <p><input name="attach" type="file" />
        
    <input id="submit" name="submit" type="submit"value="上传"/>
      
    </p>
    </form>


    controller:

    def create
        @attachment 
    = Attachment.new(:uploaded_data =>params[:attach])
        respond_to do 
    |format|
          
    if @attachment.save!
            flash[:notice] 
    = 'Attachment was successfully created.'
            format.html { redirect_to(@attachment) }
            format.xml  { render :xml 
    => @attachment, :status => :created, :location => @attachment }
          
    else
            format.html { render :action 
    => "new" }
            format.xml  { render :xml 
    => @attachment.errors, :status => :unprocessable_entity }
          end
        end
      end

     

    attachment使用起来很方便,但是其配置比较麻烦,主要是readme文档写的不够全面。所以就会出现一些奇怪的问题。

    <1>问题1,其文件名莫名多了几级文件目录。如:/0000/0006/

    #文件名

    /attachments/2009/10/30/0000/0006/Lighthouse.jpg


    但是我并没有定义余下的目录“/0000/0006/”,这并不是我想要,为什么会出现呢?

    原因:
    一个目录下的文件是有限的,所以,作者采用了一种机制,使得文件分多个目录进行存储,在这里用到了id,如果id是integer,会自动将id拆分为两个,例如:id=9,则其存储即为:/0000/0009/。具体大家可以参照:attachment_fu/lib/attachment_fu/bakends/file_system_backend.rb文件full_filename即为文件存储的全路径,处理分区的方法即为:partitioned_path,上面有陈述,可以细细看看。

    解决方法:

    如果你不需要这种分目录的机制,

    一种方法是重写full_filename,

    一种就是直接在has_attachment里面加入:partition => false 验证即可。


    现在的目录就可以完全操控了。

    Attachment_fu will delete them automatically.

    参照:http://9esuluciano.javaeye.com/blog/137056

    <2>在上传的时候,偶尔会出现一个验证错误:

    Validation failed: Size is not included in the list
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:1090:in `save_without_dirty!'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/dirty.rb:87:in `save_without_transactions!'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in `save!'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:182:in `transaction'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in `save!'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
    c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:200:in `save!'
    D:/Project/RubyProjects/attachment_test/app/controllers/attachments_controller.rb:46:in `create'
    D:/Project/RubyProjects/attachment_test/app/controllers/attachments_controller.rb:45:in `create'

    原因与解决方案:

    它models配置中的:min_size如果不设置位为0,在windows环境下,由于文件处理过程相对较长,所以取不到文件的大小,导致文件大小校验失败,只有把:min_size设为0,校验可以通过。

    <3>文件重命名

    在存储文件的时候,如果是中文名,经常出错,需要进行重命名。解决方案如下:

    Code
      protected
      before_save :assign
      
    #功能:重新命名、记录存储地址
      #流程:
      #1、记录原始文件名
      #2、重新命名
      #3、记录相对地址
      def assign
        self.org_filename 
    = self.filename
        self.filename 
    = Time.now.strftime('%Y%m%d-%H%M%S'+ "." + self.filename.split('.')[1]
        self.relative_url 
    = self.public_filename
      end

    <4>public_filename并非存储路径,public_filename是根据path_prefix和filename拼出来的。

    如果指定的path_prefix的是固定的,public_filename就是文件的存储路径,

    如果path_prefix是变量,就像我上面设置的随时间的改变而改变,那么public_filename就不能标识文件的存储路径,就需要定义一个新的字段来存储。

    <5>如果上传中文名的文件,你会看到存储的文件名类似于“____.jpg”

    原因:attachment_fu在对文件名进行了限制处理。

    在attachment_fu.rb文件中有一个方法:

    def sanitize_filename(filename)
    return unless filename
    returning filename
    .strip do |name|
    # NOTE: File.basename doesn't work right with Windows paths on Unix
    # get only the filename, not the whole path

    name.gsub! /^.*(\\|\/)/, ''

    # Finally, replace all non alphanumeric, underscore or periods with underscore
    name.gsub! /[^A-Za-z0-9\.\-]/, '_'
    end
    end
    解决方法:

    如果为了记录中文

    1、修改此方法,注释掉:name.gsub! /[^A-Za-z0-9\.\-]/, '_'

    2、在上传直接记录原始文件名

    @attachment = Attachment.new(:uploaded_data =>params[:attachment])
    @attachment.org_filename = params[:attachment].original_filename

  • 相关阅读:
    面试题--基础
    面试题---flask
    vue---07 支付和订单
    企业真题
    vue --06 购物车的实现
    Three.js 开发机房(四)
    Three.js 开发机房(三)
    Three.js 开发机房(二)
    Three.js 开发机房(一)
    Three.js 前言
  • 原文地址:https://www.cnblogs.com/yank/p/attachment.html
Copyright © 2020-2023  润新知