Module: Technoweenie::AttachmentFu::Backends::FtpBackend

Defined in:
lib/technoweenie/attachment_fu/backends/ftp_backend.rb

Overview

Ftp Storage Backend

Enables use of an ftp server for storage. (Adapted s3 backend to the ftp scenario)

Configuration

Configuration is done via RAILS_ROOT/config/attachment_fu_ftp.yml and is loaded according to the RAILS_ENV. The minimum connection options that you must specify are, the ftp login and password.

Example configuration (RAILS_ROOT/config/attachment_fu_ftp.yml) (Not sure how ftp-library supports ports different from standard FTP port)

development:
  server: hostname
  login: <your login>
  password: <your password>
  base_upload_path: <path on ftp server>
  base_url: <url where files can be read after uploading>

test:
  server: hostname
  login: <your login>
  password: <your password>
  base_upload_path: <path on ftp server>
  base_url: <url where files can be read after uploading>

production:
  server: hostname
  login: <your login>
  password: <your password>
  base_upload_path: <path on ftp server>
  base_url: <url where files can be read after uploading>

You can change the location of the config path by passing a full path to the :ftp_config_path option.

has_attachment :storage => :ftp, :ftp_config_path => (RAILS_ROOT + '/config/attachment_fu_ftp.yml')

Required configuration parameters

  • :login - The login for your ftp account.

  • :password - The password for your ftp account.

  • :base_upload_path - Base directory on ftp server

If any of these required arguments is missing, an exception will be raised.

Optional configuration parameters

Usage

To specify ftp as the storage mechanism for a model, set the acts_as_attachment :storage option to :ftp.

class Photo < ActiveRecord::Base
  has_attachment :storage => :ftp
end

Customizing the path

By default, files are prefixed using a pseudo hierarchy in the form of :table_name/:id, which results in urls that look like: [base_url]/:table_name/:id/:filename with :table_name representing the customizable portion of the path. You can customize this prefix using the :path_prefix option:

class Photo < ActiveRecord::Base
  has_attachment :storage => :ftp, :path_prefix => 'my/custom/path'
end

Which would result in URLs like [base_url]/my/custom/path/:id/:filename

Other options

Of course, all the usual configuration options apply, such as content_type and thumbnails:

class Photo < ActiveRecord::Base
  has_attachment :storage => :ftp, :content_type => ['application/pdf', :image], :resize_to => 'x50'
  has_attachment :storage => :ftp, :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }
end

Accessing FTP URLs

You can get an object’s URL using the ftp_url accessor. For example, assuming that for your postcard app you had a path_prefix like ‘postcard_world_development’, and an attachment model called Photo:

@postcard.ftp_url # => [base_url]/postcard_world_development/photos/1/mexico.jpg

Defined Under Namespace

Classes: ConfigFileNotFoundError, RequiredLibraryNotFoundError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 94

def self.included(base) #:nodoc:
  mattr_reader :ftp_config,
               :base_upload_path

  begin
    require 'net/ftp'
  rescue LoadError
    raise RequiredLibraryNotFoundError.new('Net::FTP could not be loaded')
  end

  begin
    @@ftp_config_path = base.attachment_options[:ftp_config_path] || (RAILS_ROOT + '/config/attachment_fu_ftp.yml')
    @@ftp_config = YAML.load(ERB.new(File.read(@@ftp_config_path)).result)[RAILS_ENV].symbolize_keys
  end

  @@base_upload_path = ftp_config[:base_upload_path]

  base.before_update :rename_file
end

Instance Method Details

#attachment_path_idObject

The attachment ID used in the full path of a file



121
122
123
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 121

def attachment_path_id
  ((respond_to?(:parent_id) && parent_id) || id)
end

#base_pathObject

The pseudo hierarchy containing the file relative to the bucket name Example: :table_name/:id



127
128
129
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 127

def base_path
  File.join(path_prefix)
end

#base_urlObject



131
132
133
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 131

def base_url
  ftp_config[:base_url] || ''
end

#create_temp_fileObject



150
151
152
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 150

def create_temp_file
  write_to_temp_file current_data
end

#current_dataObject



154
155
156
157
158
159
160
161
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 154

def current_data
  Net::FTP.open(ftp_config[:server]) do |ftp|
    ftp.(ftp_config[:login], ftp_config[:password])
    ftp.getbinaryfile(File.join(ftp_config[:base_upload_path], full_filename)) do |data|
      return data
    end
  end
end

#filename=(value) ⇒ Object

Overwrites the base filename writer in order to store the old filename



115
116
117
118
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 115

def filename=(value)
  @old_filename = filename unless filename.nil? || @old_filename
  write_attribute :filename, sanitize_filename(value)
end

#ftp_url(thumbnail = nil) ⇒ Object Also known as: public_filename



145
146
147
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 145

def ftp_url(thumbnail = nil)
  File.join(ftp_config[:base_url], full_filename(thumbnail))
end

#full_filename(thumbnail = nil) ⇒ Object

The full path to the file relative to the bucket name Example: :table_name/:id/:filename



141
142
143
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 141

def full_filename(thumbnail = nil)
  File.join(base_path, *partitioned_path(thumbnail_name_for(thumbnail)))
end

#partitioned_path(*args) ⇒ Object

Partitions the given path into an array of path components.

For example, given an *args of [“foo”, “bar”], it will return ["0000", "0001", "foo", "bar"] (assuming that that id returns 1).

If the id is not an integer, then path partitioning will be performed by hashing the string value of the id with SHA-512, and splitting the result into 4 components. If the id a 128-bit UUID (as set by :uuid_primary_key => true) then it will be split into 2 components.

To turn this off entirely, set :partition => false.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 174

def partitioned_path(*args)
  if respond_to?(:attachment_options) && attachment_options[:partition] == false 
    args
  elsif attachment_options[:uuid_primary_key]
    # Primary key is a 128-bit UUID in hex format. Split it into 2 components.
    path_id = attachment_path_id.to_s
    component1 = path_id[0..15] || "-"
    component2 = path_id[16..-1] || "-"
    [component1, component2] + args
  else
    path_id = attachment_path_id
    if path_id.is_a?(Integer)
      # Primary key is an integer. Split it after padding it with 0.
      ("%08d" % path_id).scan(/..../) + args
    else
      # Primary key is a String. Hash it, then split it into 4 components.
      hash = Digest::SHA512.hexdigest(path_id.to_s)
      [hash[0..31], hash[32..63], hash[64..95], hash[96..127]] + args
    end
  end
end

#path_prefixObject



135
136
137
# File 'lib/technoweenie/attachment_fu/backends/ftp_backend.rb', line 135

def path_prefix
  attachment_options[:path_prefix] || ''
end