Comment puis-je définir le mécanisme de stockage du papier en fonction de l’environnement Rails actuel?

J’ai une application de rails qui a plusieurs modèles avec des pièces jointes de trombone qui sont toutes téléchargées sur S3. Cette application a également une grande suite de tests qui est exécutée assez souvent. L’inconvénient est qu’une tonne de fichiers sont téléchargés sur notre compte S3 à chaque test, ce qui rend la suite de tests lente. Cela ralentit également le développement et nécessite une connexion Internet pour travailler sur le code.

Existe-t-il un moyen raisonnable de définir le mécanisme de stockage des trombones en fonction de l’environnement Rails? Idéalement, nos environnements de test et de développement utiliseraient le stockage de système de fichiers local et l’environnement de production utiliserait le stockage S3.

J’aimerais aussi extraire cette logique dans un module partagé quelconque, car nous avons plusieurs modèles qui auront besoin de ce comportement. Je voudrais éviter une solution comme celle-ci dans chaque modèle:

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

Mise à jour: la partie la plus délicate est que les options :path et :url la pièce jointe doivent différer selon le système de stockage utilisé.

Tout conseil ou suggestion serait grandement apprécié! 🙂

J’aime mieux la suggestion de Barry et rien ne vous empêche de définir la variable comme un hachage, qui peut ensuite être fusionné avec les options du trombone.

Dans config / environnements / development.rb et test.rb, définissez quelque chose comme

 PAPERCLIP_STORAGE_OPTIONS = {} 

Et dans config / environnements / production.rb

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

Enfin dans votre modèle de trombone:

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

Mise à jour: Une approche similaire a été récemment mise en œuvre dans les applications Paperclip for Rails 3.x. Les parameters spécifiques à l’environnement peuvent maintenant être définis avec config.paperclip_defaults = {:storage => :s3, ...} .

Vous pouvez définir des données de configuration globales par défaut dans les fichiers de configuration spécifiques à l’environnement. Par exemple, dans config / environnements / 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'] } }) 

Après en avoir joué pendant un moment, je suis arrivé avec un module qui fait ce que je veux.

Dans 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 ssortingng 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 

(Remarque: j’utilise certaines interpolations de trombones personnalisées ci-dessus, telles que :uuid_partition :uuid et :s3_authenticated_url . Vous devrez modifier les éléments nécessaires pour votre application particulière

Maintenant, pour chaque modèle qui a des pièces jointes de trombone, il vous suffit d’inclure ce module partagé et d’appeler la méthode has_attachment (au lieu de has_attached_file de has_attached_file )

Un exemple de fichier modèle: app/models/user.rb :

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

Avec ceci en place, vous aurez des fichiers enregistrés dans les emplacements suivants, selon votre environnement:

Développement:

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

Tester:

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

Production:

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

Cela fait exactement ce que je recherche, j’espère que cela sera utile à quelqu’un d’autre aussi. 🙂

-John

Que dis-tu de ça:

  1. Les valeurs par défaut sont définies dans application.rb. Le stockage par défaut de: fileystem est utilisé, mais la configuration de s3 est initialisée
  2. Production.rb active: le stockage s3 et modifie le chemin par défaut

Application.rb

 config.paperclip_defaults = { :hash_secret => "LongSecretSsortingng", :s3_protocol => "https", :s3_credentials => "#{Rails.root}/config/aws_config.yml", :styles => { :original => "1024x1024>", :large => "600x600>", :medium => "300x300>", :thumb => "100x100>" } } 

Development.rb (décommentez ceci pour essayer avec s3 en mode développement)

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

Production.rb:

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

Dans votre modèle:

 has_attached_file :avatar 

Ne pourriez-vous pas simplement définir une variable d’environnement dans production / test / development.rb?

 PAPERCLIP_STORAGE_MECHANISM = :s3 

Alors:

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

Ma solution est la même avec @runesoerensen répondre:

Je crée un module PaperclipStorageOption dans config/initializers/paperclip_storage_option.rb Le code est très 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 

et l’utiliser dans notre modèle has_attached_file :avatar, { :styles => { :medium => "1200x800>" } }.merge(PaperclipStorageOption.options)

Juste ça, j’espère que cette aide

Utilisez l’interpolation: rails_env lorsque vous définissez le chemin de la pièce jointe:

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