web-dev-qa-db-ja.com

現在のRails環境に基づいてPaperclipのストレージメカニズムを設定するにはどうすればよいですか?

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オプションは、使用されているストレージシステムに応じて異なる必要があります。

アドバイスや提案は大歓迎です! :-)

75
John Reilly

しばらくそれをいじった後、私がやりたいことをするモジュールを思いつきました。

内部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

これはまさに私が探しているものです。うまくいけば、他の人にも役立つことを願っています。 :)

-ジョン

27
John Reilly

私はバリーの提案が気に入っており、変数をハッシュに設定することを妨げるものは何もありません。それを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, ...}で設定できるようになりました。

78
runesoerensen

環境固有の構成ファイルにグローバルなデフォルト構成データを設定できます。たとえば、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']
  }
})
32

これはどう:

  1. デフォルトはapplication.rbで確立されます。 :filesystemのデフォルトのストレージが使用されますが、s3の構成は初期化されます
  2. Production.rbは:s3ストレージを有効にし、デフォルトのパスを変更します

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 
5
John Naegle

Production/test/development.rbに環境変数を設定するだけではできませんか?

Paperclip_STORAGE_MECHANISM = :s3

次に:

has_attached_file :image, :styles => {...},
                  :storage => Paperclip_STORAGE_MECHANISM,
                  # ...etc...
2
Barry Hess

私の解決策は@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)

ちょうど、この助けを願っています

0
duykhoa