Class: HasImage::Storage

Inherits:
Object
  • Object
show all
Defined in:
lib/has_image/storage.rb

Overview

Filesystem storage for the HasImage gem. The methods that HasImage inserts into ActiveRecord models only depend on the public methods in this class, so it should be reasonably straightforward to implement a different storage mechanism for Amazon AWS, Photobucket, DBFile, SFTP, or whatever you want.

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Storage) initialize(options)

The constuctor should be invoked with the options set by has_image.



52
53
54
# File 'lib/has_image/storage.rb', line 52

def initialize(options) # :nodoc:
  @options = options
end

Instance Attribute Details

- (Object) image_data

Returns the value of attribute image_data



17
18
19
# File 'lib/has_image/storage.rb', line 17

def image_data
  @image_data
end

- (Object) options

Returns the value of attribute options



17
18
19
# File 'lib/has_image/storage.rb', line 17

def options
  @options
end

- (Object) temp_file

Returns the value of attribute temp_file



17
18
19
# File 'lib/has_image/storage.rb', line 17

def temp_file
  @temp_file
end

Class Method Details

+ (Object) generated_file_name(*args)

By default, simply accepts and returns the id of the object. This is here to allow you to monkey patch this method, for example, if you wish instead to generate and return a UUID.



46
47
48
# File 'lib/has_image/storage.rb', line 46

def generated_file_name(*args)
  return args.first.to_param.to_s
end

+ (Object) id_from_partitioned_path(partitioned_path)



33
34
35
# File 'lib/has_image/storage.rb', line 33

def id_from_partitioned_path(partitioned_path)
  partitioned_path.join.to_i
end

+ (Object) id_from_path(path)



37
38
39
40
41
# File 'lib/has_image/storage.rb', line 37

def id_from_path(path)
  path = path.split('/') if path.is_a?(String)
  path_partitions = 2
  id_from_partitioned_path(path.first(path_partitions))
end

+ (Object) partitioned_path(id, *args)

Jamis Buck’s well known solution to this problem fails with high ids, such as those created by db:fixture:load. This version scales to large ids more gracefully. Thanks to Adrian Mugnolo for the fix. ++ FIXME: collides with IDs with more than 8 digits –



29
30
31
# File 'lib/has_image/storage.rb', line 29

def partitioned_path(id, *args)
  ["%04d" % ((id.to_i / 1e4) % 1e4), "%04d" % (id.to_i % 1e4)].concat(args)
end

Instance Method Details

- (Object) escape_file_name_for_http(webpath)



107
108
109
110
# File 'lib/has_image/storage.rb', line 107

def escape_file_name_for_http(webpath)
  dir, file = File.split(webpath)
  File.join(dir, CGI.escape(file))
end

- (Object) filesystem_path_for(object, thumbnail = nil)

Gets the full local filesystem path for an image. For example:

/var/sites/example.com/production/public/photos/0000/0001/3er0zs.jpg


146
147
148
# File 'lib/has_image/storage.rb', line 146

def filesystem_path_for(object, thumbnail = nil)
  File.join(path_for(object.has_image_id), file_name_for(object.send(options[:column]), thumbnail))
end

- (Object) generate_thumbnail(id, name, thumb_name)

Raises:



132
133
134
135
136
137
138
139
140
141
# File 'lib/has_image/storage.rb', line 132

def generate_thumbnail(id, name, thumb_name)
  size_spec = options[:thumbnails][thumb_name.to_sym]
  raise StorageError unless size_spec
  ensure_directory_exists!(id)
  File.open absolute_path(id, name, thumb_name), "w" do |thumbnail_destination|
    processor.process absolute_path(id, name), size_spec do |thumbnail_data|
      thumbnail_destination.write thumbnail_data
    end
  end
end

- (Object) generate_thumbnails(id, name) Also known as: regenerate_thumbnails

Write the thumbnails to the install directory - probably somewhere under RAILS_ROOT/public.



126
127
128
129
# File 'lib/has_image/storage.rb', line 126

def generate_thumbnails(id, name)
  ensure_directory_exists!(id)
  options[:thumbnails].keys.each { |thumb_name| generate_thumbnail(id, name, thumb_name) }
end

- (Boolean) image_too_big?

Is uploaded file larger than the allowed maximum?



77
78
79
80
# File 'lib/has_image/storage.rb', line 77

def image_too_big?
  @temp_file.open if @temp_file.closed?
  @temp_file.size > options[:max_size]
end

- (Boolean) image_too_small?

Is uploaded file smaller than the allowed minimum?



71
72
73
74
# File 'lib/has_image/storage.rb', line 71

def image_too_small?
  @temp_file.open if @temp_file.closed?
  @temp_file.size < options[:min_size]
end

- (Object) install_images(object)

Invokes the processor to resize the image(s) and the installs them to the appropriate directory.



84
85
86
87
88
89
90
91
92
# File 'lib/has_image/storage.rb', line 84

def install_images(object)
  generated_name = Storage.generated_file_name(object)
  install_main_image(object.has_image_id, generated_name)
  generate_thumbnails(object.has_image_id, generated_name) if thumbnails_needed?
  return generated_name
ensure
  @temp_file.close! if !@temp_file.closed?
  @temp_file = nil
end

- (Object) measure(path, dimension)

Measures the given dimension using the processor



95
96
97
# File 'lib/has_image/storage.rb', line 95

def measure(path, dimension)
  processor.measure(path, dimension)
end

- (Object) public_path_for(object, thumbnail = nil)

Gets the “web” path for an image. For example:

/photos/0000/0001/3er0zs.jpg


102
103
104
105
# File 'lib/has_image/storage.rb', line 102

def public_path_for(object, thumbnail = nil)
  webpath = filesystem_path_for(object, thumbnail).gsub(/\A.*public/, '')
  escape_file_name_for_http(webpath)
end

- (Object) remove_images(object, name)

Deletes the images and directory that contains them.



113
114
115
116
117
# File 'lib/has_image/storage.rb', line 113

def remove_images(object, name)
  FileUtils.rm Dir.glob(File.join(path_for(object.has_image_id), name + '*'))
  Dir.rmdir path_for(object.has_image_id)
rescue SystemCallError
end

- (Boolean) valid?

Is the uploaded file within the min and max allowed sizes?



120
121
122
# File 'lib/has_image/storage.rb', line 120

def valid?
  !(image_too_small? || image_too_big?)
end