Pregunta ¿Cómo puedo configurar el mecanismo de almacenamiento del clip basado en el entorno actual de Rails?


Tengo una aplicación de rieles que tiene varios modelos con archivos adjuntos de clip que están cargados en S3. Esta aplicación también tiene un gran conjunto de pruebas que se ejecuta con bastante frecuencia. La desventaja de esto es que una tonelada de archivos se cargan en nuestra cuenta S3 en cada ejecución de prueba, lo que hace que el banco de pruebas se ejecute lentamente. También ralentiza el desarrollo un poco, y requiere que tengas una conexión a Internet para trabajar en el código.

¿Hay alguna forma razonable de configurar el mecanismo de almacenamiento de clips basado en el entorno Rails? Idealmente, nuestros entornos de prueba y desarrollo utilizarían el almacenamiento del sistema de archivos local, y el entorno de producción usaría el almacenamiento S3.

También me gustaría extraer esta lógica en un módulo compartido de algún tipo, ya que tenemos varios modelos que necesitarán este comportamiento. Me gustaría evitar una solución como esta dentro de cada modelo:

### 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

Actualizar: La parte adhesiva es que el archivo adjunto :path y :url las opciones deben diferir según el sistema de almacenamiento que se utilice.

¡Cualquier consejo o sugerencia será bien recibido! :-)


75
2018-04-01 17:18


origen


Respuestas:


Me gusta más la sugerencia de Barry y no hay nada que te impida establecer la variable en un hash, que luego se puede fusionar con las opciones de clip.

En config / environments / development.rb y test.rb establece algo así como

PAPERCLIP_STORAGE_OPTIONS = {}

Y en config / environments / production.rb

PAPERCLIP_STORAGE_OPTIONS = {:storage => :s3, 
                               :s3_credentials => "#{Rails.root}/config/s3.yml",
                               :path => "/:style/:filename"}

Finalmente en su modelo de clip:

has_attached_file :image, {
    :styles => {:thumb => '50x50#', :original => '800x800>'}
}.merge(PAPERCLIP_STORAGE_OPTIONS)

Actualizar: Un enfoque similar fue recientemente implementado en Paperclip para aplicaciones Rails 3.x. La configuración específica del entorno ahora se puede configurar con config.paperclip_defaults = {:storage => :s3, ...}.


78
2017-08-10 20:22



Puede establecer datos de configuración globales por defecto en los archivos de configuración específicos del entorno. Por ejemplo, en 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
2018-06-11 01:42



Después de jugar con esto por un tiempo, se me ocurrió un módulo que hace lo que quiero.

Dentro 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

(Nota: estoy usando algunas interpolaciones de clip personalizadas arriba, como :uuid_partition, :uuid y :s3_authenticated_url. Tendrá que modificar las cosas según sea necesario para su aplicación en particular)

Ahora, para cada modelo que tenga archivos adjuntos de clip, solo tiene que incluir este módulo compartido y llamar al has_attachment método (en lugar de paperclip's has_attached_file)

Un ejemplo de archivo de modelo: app/models/user.rb:

class User < ActiveRecord::Base
  include Shared::AttachmentHelper  
  has_attachment :avatar, :styles => { :thumbnail => "100x100>" }
end

Con esto en su lugar, tendrá los archivos guardados en las siguientes ubicaciones, dependiendo de su entorno:

Desarrollo: 

RAILS_ROOT + public/attachments/development/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg

Prueba:

RAILS_ROOT + public/attachments/test/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg

Producción:

https://s3.amazonaws.com/your-bucket-name/user_avatars/aa/bb/cc/aabbccddeeff/thumbnail.jpg

Esto hace exactamente lo que estoy buscando, con suerte también será útil para otros. :)

-John


27
2018-04-02 19:23



Qué tal esto:

  1. Los valores predeterminados se establecen en application.rb. Se utiliza el almacenamiento predeterminado de: sistema de archivos, pero la configuración de s3 se inicializa
  2. Production.rb habilita: s3 storage y cambia la ruta predeterminada

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 (elimine esto para probar con s3 en modo de desarrollo)

# config.paperclip_defaults.merge!({
#   :storage => :s3,
#   :bucket => "mydevelopmentbucket",
#   :path => ":hash.:extension"
# })

Production.rb:

config.paperclip_defaults.merge!({
  :storage => :s3,
  :bucket => "myproductionbucket",
  :path => ":hash.:extension"
})

En tu modelo:

has_attached_file :avatar 

5
2018-06-22 18:54



¿No podría simplemente establecer una variable de entorno en production / test / development.rb?

PAPERCLIP_STORAGE_MECHANISM = :s3

Entonces:

has_attached_file :image, :styles => {...},
                  :storage => PAPERCLIP_STORAGE_MECHANISM,
                  # ...etc...

2
2018-04-01 17:56



Mi solución es la misma con @runesoerensen respuesta:

Yo creo un modulo PaperclipStorageOption en config/initializers/paperclip_storage_option.rb El código es muy simple:

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

y usarlo en nuestro modelo has_attached_file :avatar, { :styles => { :medium => "1200x800>" } }.merge(PaperclipStorageOption.options)

Solo eso, espero que esto ayude


0
2018-02-17 03:55



Utilice la interpolación: rails_env cuando defina la ruta del archivo adjunto:

has_attached_file :attachment, :path => ":rails_root/storage/:rails_env/attachments/:id/:style/:basename.:extension"

-4
2018-01-18 10:39