Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Sean Cribbs http://seancribbs.com

« Newer Snippets
Older Snippets »
Showing 1-4 of 4 total  RSS 

Make a remote URL work like a file upload (in Rails)

Want to load a remote URL into an acts_as_attachment/attachment_fu model? Use this little utility class.

  class UrlUpload
    EXTENSIONS = {
      "image/jpeg" => ["jpg", "jpeg", "jpe"],
      "image/gif" => ["gif"],
      "image/png" => ["png"]
    }
    attr_reader :original_filename, :attachment_data
    def initialize(url)
      @attachment_data = open(url)
      @original_filename = determine_filename
    end

    # Pass things like size, content_type, path on to the downloaded file
    def method_missing(symbol, *args)
      if self.attachment_data.respond_to? symbol
        self.attachment_data.send symbol, *args
      else
        super
      end
    end
    
    private
      def determine_filename
        # Grab the path - even though it could be a script and not an actual file
        path = self.attachment_data.base_uri.path
        # Get the filename from the path, make it lowercase to handle those
        # crazy Win32 servers with all-caps extensions
        filename = File.basename(path).downcase
        # If the file extension doesn't match the content type, add it to the end, changing any existing .'s to _
        filename = [filename.gsub(/\./, "_"), EXTENSIONS[self.content_type].first].join(".") unless EXTENSIONS[self.content_type].any? {|ext| filename.ends_with?("." + ext) }
        # Return the result
        filename
      end
  end


Now when you have the URL you want to load, do something like this:

@model.uploaded_data = UrlUpload.new(url)


Or better yet, make a pseudo-accessor on your aaa/attachment_fu model so you can stay "model-heavy".

def url=(value)
  self.uploaded_data = UrlUpload.new(value)
end

Compress your ActiveRecord sessions

Using ActiveRecordStore and your sessions are getting too big? Try this!

# in environment.rb or some file you require
require 'zlib'
CGI::Session::ActiveRecordStore::Session.class_eval {
  class << self
    def marshal_with_compression(data)
      Zlib::Deflate.deflate(marshal_without_compression(data))
    end
    def unmarshal_with_compression(data)
      unmarshal_without_compression(Zlib::Inflate.inflate(data))
    end
    alias_method_chain :marshal, :compression
    alias_method_chain :unmarshal, :compression
  end
}

# in migration
def self.up
  change_column :sessions, :data, :binary
end

def self.down
  change_column :sessions, :data, :text
end

Turn CSV with headers into Array of Hashes (in 5 lines or less)

This assumes you have a CSV file whose first line are headings/labels for the individual columns.

require 'csv'

csv_data = CSV.read 'data.csv'
headers = csv_data.shift.map {|i| i.to_s }
string_data = csv_data.map {|row| row.map {|cell| cell.to_s } }
array_of_hashes = string_data.map {|row| Hash[*headers.zip(row).flatten] }

Home-brewed file upload in Ruby on Rails

Most of this comes from others' work, but I was able to tool it to my needs and fix some bugs. All of these lines go in the model, which for me has a :file and :content_type attributes. :file stores the complete path to the uploaded file. Be sure to change the string in path_to_file to the place where you want files stored, and that proper permissions are set on that path. Also, sanitize_filename doesn't HAVE to be a private method -- make it public if you want.

### Model ###
 def file=(uploaded_file)  
    @uploaded_file = uploaded_file
    @filename = sanitize_filename(@uploaded_file.original_filename)
    write_attribute("content_type", @uploaded_file.content_type)
  end
  
  def after_create
    if !File.exists?(File.dirname(path_to_file))
      Dir.mkdir(File.dirname(path_to_file))
    end
    if @uploaded_file.instance_of?(Tempfile)
      FileUtils.copy(@uploaded_file.local_path, path_to_file)
    else
      File.open(self.path_to_file, "wb") { |f| f.write(@uploaded_file.read) }
    end
    write_attribute("file", path_to_file)
  end

  def after_destroy
    if File.exists?(self.file)
      File.delete(self.file)
      Dir.rmdir(File.dirname(self.file))
    end
  end
  
  def path_to_file
    File.expand_path("#{RAILS_ROOT}/upload/#{self.id}/#{@filename}")
  end
  
  private
  def sanitize_filename(file_name)
    # get only the filename, not the whole path (from IE)
    just_filename = File.basename(file_name) 
    # replace all none alphanumeric, underscore or perioids with underscore
    just_filename.gsub(/[^\w\.\_]/,'_') 
  end
  
### View ###
...
<input type="file" name="model[file]" />
...
« Newer Snippets
Older Snippets »
Showing 1-4 of 4 total  RSS