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

#initialize(options) ⇒ Storage

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

#image_dataObject

Returns the value of attribute image_data



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

def image_data
  @image_data
end

#optionsObject

Returns the value of attribute options



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

def options
  @options
end

#temp_fileObject

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

.generated_file_name(*args) ⇒ Object

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

.id_from_partitioned_path(partitioned_path) ⇒ Object



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

def id_from_partitioned_path(partitioned_path)
  partitioned_path.join.to_i
end

.id_from_path(path) ⇒ Object



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

.partitioned_path(id, *args) ⇒ Object

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

#escape_file_name_for_http(webpath) ⇒ Object



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

#filesystem_path_for(object, thumbnail = nil) ⇒ Object

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

#generate_thumbnail(id, name, thumb_name) ⇒ Object

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

#generate_thumbnails(id, name) ⇒ Object 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

#image_too_big?Boolean

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

#image_too_small?Boolean

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

#install_images(object) ⇒ 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

#measure(path, dimension) ⇒ Object

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

#public_path_for(object, thumbnail = nil) ⇒ Object

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

#remove_images(object, name) ⇒ Object

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

#valid?Boolean

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