1. ホーム
  2. ruby-on-rails

現在のRails環境に基づいてpaperclipのストレージ機構を設定するにはどうすればよいですか?

2023-09-15 23:18:52

質問

私は、S3にアップロードされたペーパークリップの添付ファイルを持つ複数のモデルを持っているRailsアプリケーションを持っています。 このアプリケーションには、かなり頻繁に実行される大規模なテスト スイートもあります。この欠点は、テスト実行のたびに大量のファイルが S3 アカウントにアップロードされ、テスト スイートの実行が遅くなることです。 また、開発速度も少し遅くなり、コードで作業するためにインターネット接続が必要になります。

Railsの環境に応じてペーパークリップのストレージ機構を設定する合理的な方法はありますか?理想的には、テストと開発環境ではローカル ファイルシステム ストレージを使用し、本番環境では 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 . 特定のアプリケーションのために、必要に応じて変更する必要があります)

これで、ペーパークリップのアタッチメントを持つすべてのモデルについて、この共有モジュールをインクルードし、その上で 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

これはまさに私が求めていたもので、他の誰かにとっても有用であることが証明されることを望みます。)

-ジョン