嵌ったのでメモ。
s3で使う
これも割と簡単です。
modelでstorageにs3、s3_credentialsをymlに定義して読み込ませます。
PaperClipを使って本番の時だけAmazon S3を使う - func09
tokyo regionで使う
ここで嵌りました。
PaperclipからAmazon S3のTokyo Regionを使うには。 - このブログは証明できない。
だいたいは↑に書かれているのですが
s3のurlが
http://s3.amazonaws.com/mybucket/
http://mybucket.s3.amazonaws.com/
だったのがtokyoだと
http://s3-ap-northeast-1.amazonaws.com/mybucket/
http:///mybucket.s3-ap-northeast-1.amazonaws.com/
となるからです。
こんなエラーになります
AWS::S3::PermanentRedirect in UsersController#create The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.
これは、aws-s3のconstを変更することで解決です。
#config/initializers/aws.rb AWS::S3::DEFAULT_HOST.replace "s3-ap-northeast-1.amazonaws.com"
しかし表示する際のurlがs3.amazonaws.comになってしまってます。
http://s3.amazonaws.com/bucket/avatars/3/original.jpeg?1302193703
ソースを見てみると
こんな感じです。
#paperclit/attachment.rb
module Paperclip class Attachment def url(style_name = default_style, use_timestamp = @use_timestamp) url = original_filename.nil? ? interpolate(@default_url, style_name) : interpolate(@url, style_name) use_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url end
def original_filename instance_read(:file_name) end
def instance_read(attr) getter = :"#{name}_#{attr}" responds = instance.respond_to?(getter) cached = self.instance_variable_get("@_#{getter}") return cached if cached instance.send(getter) if responds || attr.to_s == "file_name" end
@urlが怪しそうです
#paperclip/storage/s3.rb module Paperclip module Storage module S3 def self.extended base begin require 'aws/s3' rescue LoadError => e e.message << " (You may need to install the aws-s3 gem)" raise e end unless defined?(AWS::S3) base.instance_eval do @s3_credentials = parse_credentials(@options[:s3_credentials]) @bucket = @options[:bucket] || @s3_credentials[:bucket] @bucket = @bucket.call(self) if @bucket.is_a?(Proc) @s3_options = @options[:s3_options] || {} @s3_permissions = @options[:s3_permissions] || :public_read @s3_protocol = @options[:s3_protocol] || (@s3_permissions == :public_read ? 'http' : 'https') @s3_headers = @options[:s3_headers] || {} @s3_host_alias = @options[:s3_host_alias] unless @url.to_s.match(/^:s3.*url$/) @path = @path.gsub(/:url/, @url) @url = ":s3_path_url" end AWS::S3::Base.establish_connection!( @s3_options.merge( :access_key_id => @s3_credentials[:access_key_id], :secret_access_key => @s3_credentials[:secret_access_key] )) end Paperclip.interpolates(:s3_alias_url) do |attachment, style| "#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}" end unless Paperclip::Interpolations.respond_to? :s3_alias_url Paperclip.interpolates(:s3_path_url) do |attachment, style| "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}" end unless Paperclip::Interpolations.respond_to? :s3_path_url Paperclip.interpolates(:s3_domain_url) do |attachment, style| "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}" end unless Paperclip::Interpolations.respond_to? :s3_domain_url end
最後の3ブロックで
urlを生成しているのが分かります。
デフォルトは、:s3_path_urlで2つめのブロックです。
なんと「s3.amazonaws.com」直書きですね。
なので
モンキーパッチ的にここを書き換えるか、:s3_alias_urlを使えばなんとかできそうです。
後者のほうでやってみた結果が下記です。
#app/models/user.rb
class User < ActiveRecord::Base has_attached_file :avatar, :storage => :s3, :s3_credentials => "#{RAILS_ROOT}/config/s3.yml", :path => ":attachment/:id/:style.:extension", :bucket => 'mybucket', :url => ":s3_alias_url", :s3_host_alias => "s3-ap-northeast-1.amazonaws.com/mybucket" end