如何根据当前的 Rails 环境设置曲别针的存储机制?

我有一个 Rails 应用程序,有多个模型与曲别针附件,都上传到 S3。这个应用程序还有一个很大的测试套件,经常运行。这样做的缺点是,每次测试运行时都会有大量文件上传到我们的 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选项需要根据使用的存储系统而有所不同。

任何建议或意见将不胜感激! : -)

23457 次浏览

你就不能在 production/test/development. rb 中设置一个环境变量吗?

PAPERCLIP_STORAGE_MECHANISM = :s3

然后:

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

在使用了一段时间之后,我想出了一个可以做我想做的事情的模块。

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

这正是我所寻找的,希望它能证明对其他人也有用。 :)

约翰

我更喜欢巴里的建议,没有什么可以阻止您设置的变量为散列,然后可以与曲别针选项合并。

在 config/environment/development.rb 和 test.rb 中设置类似于

PAPERCLIP_STORAGE_OPTIONS = {}

在 config/Environment/production.rb 中

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

最后,在你的回形针模型中:

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

更新: 最近针对 Rails 3. x 应用程序的 以回形针实施也采用了类似的方法,现在可以用 config.paperclip_defaults = {:storage => :s3, ...}设置特定于环境的设置。

您可以在特定于环境的配置文件中设置全局默认配置数据:

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']
}
})

在定义附件路径时使用: ails _ env 插值:

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

这样吧:

  1. 默认设置是在 application.rb 中建立的,使用了: filessystem 的默认存储,但是初始化了 s3的配置
  2. Rb 启用: s3存储并更改默认路径

申请 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>"
}
}

Rb (取消注释以在开发模式下尝试使用 s3)

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

制片:

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

在你的模型中:

has_attached_file :avatar

我的解决方案与@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 _ ached _ file: 化身,{ : style = > { : media = > “1200x800 >”}} . merge (PaperclipStorageOption.options)

只是,希望这个能帮上忙