Как я могу установить механизм хранения скрепки на основе текущей среды направляющих?

У меня есть приложение направляющих, которое имеет многоуровневые модели с вложениями скрепки, которые все загружаются на S3. Это приложение также имеет большой набор тестов, который выполняется довольно часто. Оборотная сторона с этим - то, что тонна файлов загружается на нашу учетную запись S3 на каждом тестовом прогоне, делая набор тестов выполняемым медленно. Это также замедляет разработку немного и требует, чтобы у Вас было интернет-соединение, для работы над кодом.

Существует ли разумный способ установить механизм хранения скрепки на основе среды направляющих? Идеально, наши тестовые среды и среды разработки использовали бы устройство хранения данных локальной файловой системы, и продуктивная среда будет использовать устройство хранения данных 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 1 April 2010 в 19:50
поделиться

3 ответа

Поигравшись с ним некоторое время, я придумал модуль, который делает то, что я хочу.

Внутри 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 (вместо скрепки 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
ответ дан 24 November 2019 в 11:37
поделиться

Не могли бы вы просто установить переменную среды в production / test / development.rb?

PAPERCLIP_STORAGE_MECHANISM = :s3

Тогда:

has_attached_file :image, :styles => {...},
                  :storage => PAPERCLIP_STORAGE_MECHANISM,
                  # ...etc...
2
ответ дан 24 November 2019 в 11:37
поделиться

Мне больше нравится предложение Барри, и ничто не мешает вам установить переменную в хэш, который затем можно объединить с опциями скрепки.

В 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)

Update: Похожий подход был недавно реализован в Paperclip для приложений Rails 3.x. Теперь специфические для среды настройки можно задать с помощью config.paperclip_defaults = {:storage => :s3, ...}.

78
ответ дан 24 November 2019 в 11:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: