class AWS::S3::Base
AWS::S3::Base is the abstract super class of all classes who make requests against S3, such as the built in Service, Bucket and S3Object classes. It provides methods for making requests, inferring or setting response classes, processing request options, and accessing attributes from S3’s response data.
Establishing a connection with the Base class is the entry point to using the library:
AWS::S3::Base.establish_connection!(:access_key_id => '...', :secret_access_key => '...')
The :access_key_id
and :secret_access_key
are the two required connection options. More details can be found in the docs for Connection::Management::ClassMethods
.
Extensive examples can be found in the README.
Attributes
Public Class Methods
Source
# File lib/aws/s3/base.rb 106 def current_bucket 107 connection.subdomain or raise CurrentBucketNotSpecified.new(connection.http.address) 108 end
Called when a method which requires a bucket name is called without that bucket name specified. It will try to infer the current bucket by looking for it as the subdomain of the current connection’s address. If no subdomain is found, CurrentBucketNotSpecified will be raised.
MusicBucket.establish_connection! :server => 'jukeboxzero.s3.amazonaws.com' MusicBucket.connection.server => 'jukeboxzero.s3.amazonaws.com' MusicBucket.current_bucket => 'jukeboxzero'
Rather than infering the current bucket from the subdomain, the current class’ bucket can be explicitly set with set_current_bucket_to.
Source
# File lib/aws/s3/base.rb 66 def request(verb, path, options = {}, body = nil, attempts = 0, &block) 67 Service.response = nil 68 process_options!(options, verb) 69 response = response_class.new(connection.request(verb, path, options, body, attempts, &block)) 70 Service.response = response 71 72 Error::Response.new(response.response).error.raise if response.error? 73 response 74 # Once in a while, a request to S3 returns an internal error. A glitch in the matrix I presume. Since these 75 # errors are few and far between the request method will rescue InternalErrors the first three times they encouter them 76 # and will retry the request again. Most of the time the second attempt will work. 77 rescue InternalError, RequestTimeout 78 if attempts == 3 79 raise 80 else 81 attempts += 1 82 retry 83 end 84 end
Wraps the current connection’s request method and picks the appropriate response class to wrap the response in. If the response is an error, it will raise that error as an exception. All such exceptions can be caught by rescuing their superclass, the ResponseError
exception class.
It is unlikely that you would call this method directly. Subclasses of Base have convenience methods for each http request verb that wrap calls to request.
Source
# File lib/aws/s3/base.rb 133 def set_current_bucket_to(name) 134 raise ArgumentError, "`#{__method__}' must be called on a subclass of #{self.name}" if self == AWS::S3::Base 135 instance_eval(<<-EVAL) 136 def current_bucket 137 '#{name}' 138 end 139 EVAL 140 end
If you plan on always using a specific bucket for certain files, you can skip always having to specify the bucket by creating a subclass of Bucket or S3Object and telling it what bucket to use:
class JukeBoxSong < AWS::S3::S3Object set_current_bucket_to 'jukebox' end
For all methods that take a bucket name as an argument, the current bucket will be used if the bucket name argument is omitted.
other_song = 'baby-please-come-home.mp3' JukeBoxSong.store(other_song, open(other_song))
This time we didn’t have to explicitly pass in the bucket name, as the JukeBoxSong class knows that it will always use the ‘jukebox’ bucket.
“Astute readers”, as they say, may have noticed that we used the third parameter to pass in the content type, rather than the fourth parameter as we had the last time we created an object. If the bucket can be inferred, or is explicitly set, as we’ve done in the JukeBoxSong class, then the third argument can be used to pass in options.
Now all operations that would have required a bucket name no longer do.
other_song = JukeBoxSong.find('baby-please-come-home.mp3')
Private Class Methods
Source
# File lib/aws/s3/base.rb 178 def bucket_name(name) 179 name || current_bucket 180 end
Source
# File lib/aws/s3/base.rb 149 def process_options!(options, verb) 150 options.replace(RequestOptions.process(options, verb)) 151 end
Source
# File lib/aws/s3/base.rb 156 def respond_with(klass) 157 eval(<<-EVAL, binding, __FILE__, __LINE__) 158 def new_response_class 159 #{klass} 160 end 161 162 class << self 163 alias_method :old_response_class, :response_class 164 alias_method :response_class, :new_response_class 165 end 166 EVAL 167 168 yield 169 ensure 170 # Restore the original version 171 eval(<<-EVAL, binding, __FILE__, __LINE__) 172 class << self 173 alias_method :response_class, :old_response_class 174 end 175 EVAL 176 end
Using the conventions layed out in the response_class
works for more than 80% of the time. There are a few edge cases though where we want a given class to wrap its responses in different response classes depending on which method is being called.
Source
# File lib/aws/s3/base.rb 145 def response_class 146 FindResponseClass.for(self) 147 end
Private Instance Methods
Source
# File lib/aws/s3/base.rb 228 def method_missing(method, *args, &block) 229 case 230 when attributes.has_key?(method.to_s) 231 attributes[method.to_s] 232 when attributes.has_key?(method) 233 attributes[method] 234 else 235 super 236 end 237 end
Source
# File lib/aws/s3/base.rb 224 def request(*args, &block) 225 self.class.request(*args, &block) 226 end