Railsアプリケーションは、S3にすべてアップロードされるPaperclip添付ファイルを含む複数のモデルを持っています。このアプリには、非常に頻繁に実行される大規模なテストスイートもあります。テスト実行のたびにS3アカウントにファイルがアップロードされ、テストスイートの実行が遅くなります。また、開発が少し遅くなり、コードを操作するためにインターネット接続が必要になります。
Rails環境に基づいてPaperclipストレージメカニズムを設定する合理的な方法はありますか?理想的には、テストおよび開発環境はローカルファイルシステムストレージを使用し、実稼働環境はS3ストレージを使用します。
また、この動作を必要とするいくつかのモデルがあるため、このロジックを何らかの種類の共有モジュールに抽出したいと思います。私はすべてのモデルの中でこのような解決策を避けたいです:
### We don't want to do this in our models...
if Rails.env.production?
has_attached_file :image, :styles => {...},
:path => "images/:uuid_partition/:uuid/:style.:extension",
:storage => :s3,
:url => ':s3_authenticated_url', # generates an expiring url
:s3_credentials => File.join(Rails.root, 'config', 's3.yml'),
:s3_permissions => 'private',
:s3_protocol => 'https'
else
has_attached_file :image, :styles => {...},
:storage => :filesystem
# Default :path and :url should be used for dev/test envs.
end
更新:粘着部分は、添付ファイルの:path
および:url
オプションは、使用されているストレージシステムに応じて異なる必要があります。
アドバイスや提案は大歓迎です! :-)
しばらくそれをいじった後、私がやりたいことをするモジュールを思いつきました。
内部app/models/shared/attachment_helper.rb
:
module Shared
module AttachmentHelper
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def has_attachment(name, options = {})
# generates a string containing the singular model name and the pluralized attachment name.
# Examples: "user_avatars" or "asset_uploads" or "message_previews"
attachment_owner = self.table_name.singularize
attachment_folder = "#{attachment_owner}_#{name.to_s.pluralize}"
# we want to create a path for the upload that looks like:
# message_previews/00/11/22/001122deadbeef/thumbnail.png
attachment_path = "#{attachment_folder}/:uuid_partition/:uuid/:style.:extension"
if Rails.env.production?
options[:path] ||= attachment_path
options[:storage] ||= :s3
options[:url] ||= ':s3_authenticated_url'
options[:s3_credentials] ||= File.join(Rails.root, 'config', 's3.yml')
options[:s3_permissions] ||= 'private'
options[:s3_protocol] ||= 'https'
else
# For local Dev/Test envs, use the default filesystem, but separate the environments
# into different folders, so you can delete test files without breaking dev files.
options[:path] ||= ":Rails_root/public/system/attachments/#{Rails.env}/#{attachment_path}"
options[:url] ||= "/system/attachments/#{Rails.env}/#{attachment_path}"
end
# pass things off to Paperclip.
has_attached_file name, options
end
end
end
end
(注:上記のカスタムペーパークリップ補間を使用しています。たとえば、:uuid_partition
、:uuid
および:s3_authenticated_url
。特定のアプリケーションの必要に応じて変更する必要があります)
これで、Paperclip添付ファイルがあるすべてのモデルについて、この共有モジュールを含めるだけで、has_attachment
メソッド(Paperclipのhas_attached_file
)
モデルファイルの例:app/models/user.rb
:
class User < ActiveRecord::Base
include Shared::AttachmentHelper
has_attachment :avatar, :styles => { :thumbnail => "100x100>" }
end
これを配置すると、環境に応じて、次の場所にファイルが保存されます。
開発:
Rails_ROOT + public/attachments/development/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
テスト:
Rails_ROOT + public/attachments/test/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
生産:
https://s3.amazonaws.com/your-bucket-name/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg
これはまさに私が探しているものです。うまくいけば、他の人にも役立つことを願っています。 :)
-ジョン
私はバリーの提案が気に入っており、変数をハッシュに設定することを妨げるものは何もありません。それをPaperclipオプションとマージできます。
Config/environments/development.rbおよびtest.rbで次のように設定します
Paperclip_STORAGE_OPTIONS = {}
Config/environments/production.rb
Paperclip_STORAGE_OPTIONS = {:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "/:style/:filename"}
最後に、Paperclipモデルで:
has_attached_file :image, {
:styles => {:thumb => '50x50#', :original => '800x800>'}
}.merge(Paperclip_STORAGE_OPTIONS)
更新:最近同様のアプローチがありました Paperclipで実装 for Rails 3.x apps環境固有の設定は、config.Paperclip_defaults = {:storage => :s3, ...}
で設定できるようになりました。
環境固有の構成ファイルにグローバルなデフォルト構成データを設定できます。たとえば、config/environments/production.rbの場合:
Paperclip::Attachment.default_options.merge!({
:storage => :s3,
:bucket => 'wheresmahbucket',
:s3_credentials => {
:access_key_id => ENV['S3_ACCESS_KEY_ID'],
:secret_access_key => ENV['S3_SECRET_ACCESS_KEY']
}
})
これはどう:
Application.rb
config.Paperclip_defaults =
{
:hash_secret => "LongSecretString",
:s3_protocol => "https",
:s3_credentials => "#{Rails.root}/config/aws_config.yml",
:styles => {
:original => "1024x1024>",
:large => "600x600>",
:medium => "300x300>",
:thumb => "100x100>"
}
}
Development.rb(これをアンコメントして、開発モードでs3を試します)
# config.Paperclip_defaults.merge!({
# :storage => :s3,
# :bucket => "mydevelopmentbucket",
# :path => ":hash.:extension"
# })
Production.rb:
config.Paperclip_defaults.merge!({
:storage => :s3,
:bucket => "myproductionbucket",
:path => ":hash.:extension"
})
モデルで:
has_attached_file :avatar
Production/test/development.rbに環境変数を設定するだけではできませんか?
Paperclip_STORAGE_MECHANISM = :s3
次に:
has_attached_file :image, :styles => {...},
:storage => Paperclip_STORAGE_MECHANISM,
# ...etc...
私の解決策は@runesoerensenの答えと同じです:
_config/initializers/Paperclip_storage_option.rb
_にモジュールPaperclipStorageOption
を作成しますコードは非常に簡単です:
_module PaperclipStorageOption
module ClassMethods
def options
Rails.env.production? ? production_options : default_options
end
private
def production_options
{
storage: :dropbox,
dropbox_credentials: Rails.root.join("config/dropbox.yml")
}
end
def default_options
{}
end
end
extend ClassMethods
end
_
モデルで使用しますhas_attached_file :avatar, { :styles => { :medium => "1200x800>" } }.merge(PaperclipStorageOption.options)
ちょうど、この助けを願っています