Module: AttachmerbFu::Backends::S3Backend

Defined in:
lib/attachmerb_fu/backends/s3_backend.rb

Overview

AWS::S3 Storage Backend

Enables use of Amazon’s Simple Storage Service as a storage mechanism

Requirements

Requires the AWS::S3 Library for S3 by Marcel Molina Jr. installed either as a gem or a as a Rails plugin.

Configuration

Configuration is done via RAILS_ROOT/config/amazon_s3.yml and is loaded according to the RAILS_ENV. The minimum connection options that you must specify are a bucket name, your access key id and your secret access key. If you don’t already have your access keys, all you need to sign up for the S3 service is an account at Amazon. You can sign up for S3 and get access keys by visiting aws.amazon.com/s3.

Example configuration (RAILS_ROOT/config/amazon_s3.yml)

development:
  bucket_name: appname_development
  access_key_id: <your key>
  secret_access_key: <your key>

test:
  bucket_name: appname_test
  access_key_id: <your key>
  secret_access_key: <your key>

production:
  bucket_name: appname
  access_key_id: <your key>
  secret_access_key: <your key>

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

has_attachment :storage => :s3, :s3_config_path => (RAILS_ROOT + '/config/s3.yml')

Required configuration parameters

  • :access_key_id - The access key id for your S3 account. Provided by Amazon.

  • :secret_access_key - The secret access key for your S3 account. Provided by Amazon.

  • :bucket_name - A unique bucket name (think of the bucket_name as being like a database name).

If any of these required arguments is missing, a MissingAccessKey exception will be raised from AWS::S3.

About bucket names

Bucket names have to be globaly unique across the S3 system. And you can only have up to 100 of them, so it’s a good idea to think of a bucket as being like a database, hence the correspondance in this implementation to the development, test, and production environments.

The number of objects you can store in a bucket is, for all intents and purposes, unlimited.

Optional configuration parameters

  • :server - The server to make requests to. Defaults to s3.amazonaws.com.

  • :port - The port to the requests should be made on. Defaults to 80 or 443 if :use_ssl is set.

  • :use_ssl - If set to true, :port will be implicitly set to 443, unless specified otherwise. Defaults to false.

Usage

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

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

Customizing the path

By default, files are prefixed using a pseudo hierarchy in the form of :table_name/:id, which results in S3 urls that look like: http(s)://:server/:bucket_name/: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 => :s3, :path_prefix => 'my/custom/path'
end

Which would result in URLs like http(s)://:server/:bucket_name/my/custom/path/:id/:filename.

Permissions

By default, files are stored on S3 with public access permissions. You can customize this using the :s3_access option to has_attachment. Available values are :private, :public_read_write, and :authenticated_read.

Other options

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

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

Accessing S3 URLs

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

@postcard.s3_url # => http(s)://s3.amazonaws.com/postcard_world_development/photos/1/mexico.jpg

The resulting url is in the form: http(s)://:server/:bucket_name/:table_name/:id/:file. The optional thumbnail argument will output the thumbnail’s filename (if any).

Additionally, you can get an object’s base path relative to the bucket root using base_path:

@photo.file_base_path # => photos/1

And the full path (including the filename) using full_filename:

@photo.full_filename # => photos/

Niether base_path or full_filename include the bucket name as part of the path. You can retrieve the bucket name using the bucket_name method.

Defined Under Namespace

Modules: ClassMethods Classes: ConfigFileNotFoundError, RequiredLibraryNotFoundError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.hostnameObject



159
160
161
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 159

def self.hostname
  @hostname ||= s3_config[:server] || AWS::S3::DEFAULT_HOST
end

.included(base) ⇒ Object

:nodoc:



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 123

def self.included(base) #:nodoc:
  mattr_reader :bucket_name, :s3_config
  
  begin
    require 'aws/s3'
    include AWS::S3
  rescue LoadError
    raise RequiredLibraryNotFoundError.new('AWS::S3 could not be loaded')
  end

  begin
    @@s3_config_path = base.attachment_options[:s3_config_path] || (RAILS_ROOT + '/config/amazon_s3.yml')
    @@s3_config = @@s3_config = YAML.load_file(@@s3_config_path)[RAILS_ENV].symbolize_keys
  #rescue
  #  raise ConfigFileNotFoundError.new('File %s not found' % @@s3_config_path)
  end

  @@bucket_name = s3_config[:bucket_name]

  Base.establish_connection!(
    :access_key_id     => s3_config[:access_key_id],
    :secret_access_key => s3_config[:secret_access_key],
    :server            => s3_config[:server],
    :port              => s3_config[:port],
    :use_ssl           => s3_config[:use_ssl]
  )

  # Bucket.create(@@bucket_name)

  base.before_update :rename_file
end

.port_stringObject



163
164
165
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 163

def self.port_string
  @port_string ||= s3_config[:port] == (s3_config[:use_ssl] ? 443 : 80) ? '' : ":#{s3_config[:port]}"
end

.protocolObject



155
156
157
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 155

def self.protocol
  @protocol ||= s3_config[:use_ssl] ? 'https://' : 'http://'
end

Instance Method Details

#attachment_path_idObject

The attachment ID used in the full path of a file



188
189
190
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 188

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

#authenticated_s3_url(*args) ⇒ Object

All private objects are accessible via an authenticated GET request to the S3 servers. You can generate an authenticated url for an object like this:

@photo.authenticated_s3_url

By default authenticated urls expire 5 minutes after they were generated.

Expiration options can be specified either with an absolute time using the :expires option, or with a number of seconds relative to now with the :expires_in option:

# Absolute expiration date (October 13th, 2025)
@photo.authenticated_s3_url(:expires => Time.mktime(2025,10,13).to_i)

# Expiration in five hours from now
@photo.authenticated_s3_url(:expires_in => 5.hours)

You can specify whether the url should go over SSL with the :use_ssl option. By default, the ssl settings for the current connection will be used:

@photo.authenticated_s3_url(:use_ssl => true)

Finally, the optional thumbnail argument will output the thumbnail’s filename (if any):

@photo.authenticated_s3_url('thumbnail', :expires_in => 5.hours, :use_ssl => true)


243
244
245
246
247
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 243

def authenticated_s3_url(*args)
  thumbnail = args.first.is_a?(String) ? args.first : nil
  options   = args.last.is_a?(Hash)    ? args.last  : {}
  S3Object.url_for(full_filename(thumbnail), bucket_name, options)
end

#base_pathObject

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



194
195
196
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 194

def base_path
  File.join(attachment_options[:path_prefix], attachment_path_id)
end

#create_temp_fileObject



249
250
251
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 249

def create_temp_file
  write_to_temp_file current_data
end

#current_dataObject



253
254
255
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 253

def current_data
  S3Object.value full_filename, bucket_name
end

#filename=(value) ⇒ Object

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



182
183
184
185
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 182

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

#full_filename(thumbnail = nil) ⇒ Object

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



200
201
202
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 200

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

#s3_hostnameObject



261
262
263
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 261

def s3_hostname
  Technoweenie::AttachmentFu::Backends::S3Backend.hostname
end

#s3_port_stringObject



265
266
267
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 265

def s3_port_string
  Technoweenie::AttachmentFu::Backends::S3Backend.port_string
end

#s3_protocolObject



257
258
259
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 257

def s3_protocol
  Technoweenie::AttachmentFu::Backends::S3Backend.protocol
end

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

All public objects are accessible via a GET request to the S3 servers. You can generate a url for an object using the s3_url method.

@photo.s3_url

The resulting url is in the form: http(s)://:server/:bucket_name/:table_name/:id/:file where the :server variable defaults to AWS::S3 URL::DEFAULT_HOST (s3.amazonaws.com) and can be set using the configuration parameters in RAILS_ROOT/config/amazon_s3.yml.

The optional thumbnail argument will output the thumbnail’s filename (if any).



214
215
216
# File 'lib/attachmerb_fu/backends/s3_backend.rb', line 214

def s3_url(thumbnail = nil)
  File.join(s3_protocol + s3_hostname + s3_port_string, bucket_name, full_filename(thumbnail))
end