在开发和生产中让 Paperclip 上传到 S3
Getting Paperclip to upload to S3 in development and production
我一直在努力让 Paperclip 将图像上传到 Amazon S3。虽然我一开始让程序运行,但它只会在本地保存(尽管存储方法设置为 s3),一旦我发现我需要覆盖默认路径,它就会因写入错误而崩溃。
我不知道它是否重要,但我正在使用 Devise 并将 profile_image
添加到用户模型。
我正在尝试关注 Herokuthis guide
这是第一个只在本地写入的设置,尽管似乎是为 S3 设置的:
user.rb
class User < ApplicationRecord
has_attached_file :profile_image, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
validates_attachment_content_type :profile_image, :content_type => /\Aimage\/.*\Z/
end
production.rb 和 development.rb
config.paperlip_defaults = {
storage: :s3,
s3_credientials: {
bucket: ENV.fetch('S3_BUCKET_NAME'),
access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
s3_region: ENV.fetch('AWS_REGION')
}
}
Paperclip.options[:command_path] = '/usr/local/bin/'
上传表格的一部分
app/views/devise/registrations/edit.html.erb
<div class="form-group">
<% if @user.profile_image.present? %>
<%= image_tag(current_user.profile_image.url(:square)) %><br />
<%= link_to 'Remove profile image', remove_profile_image_path, method: :put, data: { confirm: 'Are you sure?' }, type: 'button' %>
<% else %>
<%= f.label :profile_image %>
<%= f.file_field :profile_image %>
<% end %>
</div>
使用此设置,Paperclip 可以工作,但它只会在本地保存图像(这在开发中和部署在 Heroku 上都是如此)。
接下来,我试图通过将此添加到
来强制显示 URL 来自 AWS
config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename'
这确实强制图像路径来自那里(当我为已经附加图像的用户刷新页面时,它被破坏了,因为没有上传图像)。但是,我删除了这张图片后,就无法再上传了。每次我尝试上传时都会收到此错误:
Errno::EACCES in Devise::RegistrationsController#update
Permission denied @ dir_s_mkdir - /users/profile_images
为了解决这个问题,我添加了一个额外的初始化程序(来自 Heroku 教程)
Paperclip::Attachment.default_options[:s3_host_name] = 's3-us-east-1.amazonaws.com'
不起作用,我尝试向 production.rb 和 development.rb 添加一行但没有成功(我尝试将两者都添加到默认散列和凭据散列)
s3_domain_url: 's3-us-east-1.amazonaws.com'
我知道这个错误是本地写错误,但是我的具体问题(除了如何做这个工作):
为什么Paperclip会忽略默认值中的存储值并保存在本地(在第一种情况下)?
为什么它试图写入我的本地磁盘(在第二种情况下)而不是上传到 S3?
更新
宝石文件
source 'https://rubygems.org'
ruby '2.3.3'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'puma', '~> 3.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'jquery-rails'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'bcrypt', '~> 3.1.7'
gem 'devise'
gem 'font-awesome-rails'
gem 'bourbon', '5.0.0.beta.7'
gem 'neat', '2.0.0'
gem 'autoprefixer-rails'
gem 'font-awesome-sass', '~> 4.7.0'
gem 'paperclip'
gem 'aws-sdk', '~> 2.3'
group :development, :test do
gem 'sqlite3'
gem 'byebug', platform: :mri
gem 'dotenv-rails'
end
group :development do
gem 'listen', '~> 3.0.5'
gem 'web-console'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'rubocop', require: false
gem 'haml-lint', require: false
end
group :test do
gem 'guard', '2.13.0'
gem 'minitest-reporters', '1.1.9'
gem 'coveralls', require: false
gem 'capybara'
gem 'factory_girl_rails', '~>4.0'
end
group :production do
gem 'pg', '0.18.4'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
您可能需要更改路径选项
PaperClip::Attachment.default_options[:path] = ":rails_root/public/system/.../the/rest/of/the/desired/path"
问题中的设置方式和使用的文档错误或对 Heroku 上的 Paperclip ~> 5.1
& AWS-SDK ~> 2.0
不再有效。
还有第二个未说明的问题,一旦它在开发中起作用就会变得明显,开发上传将覆盖生产上传,反之亦然。
这是对我有用的设置,使用同时上传到 S3 的开发环境和生产环境。
- 将初始化程序精简为仅共享信息
config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:path] = ':class/:attachment/:id_partition/:style/:filename'
Paperclip::Attachment.default_options[:storage] = :s3
Paperclip::Attachment.default_options[:s3_protocol] = 'https'
- 在用户模型中定义和有效图像和图像尺寸
app/model/users.rb
has_attached_file :profile_image, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
validates_attachment_content_type :profile_image, :content_type => /\Aimage\/.*\Z/
- 注册第二个开发映像存储桶并将必要的变量添加到 .ENV 文件
.ENV
# Shared S3 variables
AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXX
# Development variables
DEV_S3_BUCKET_NAME=your-dev-bucket-name
# Production variables
S3_BUCKET_NAME=your-production-bucket-name
- 将默认选项和命令路径放入各自的环境文件中
config/environments/development.rb
Paperclip::Attachment.default_options[:s3_credentials] = {
:bucket => ENV['DEV_S3_BUCKET_NAME'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
:region => 'us-east-2'
}
Paperclip::Attachment.default_options[:s3_region] = 'us-east-2'
Paperclip::Attachment.default_options[:s3_host_name] = 's3.us-east-2.amazonaws.com'
Paperclip.options[:command_path] = 'usr/local/bin'
在我的例子中,我对区域和主机名进行了硬编码,如果需要,您可以提取它们。我还选择在不同的区域托管开发映像,只是为了更加分离。另请注意,我创建的第一个存储桶(生产)不会将区域附加到地址。我不确定为什么 S3 是这样配置的,但是您可以通过上传图像然后在 AWS 控制台的文件夹中向下钻取来检查您的特定图像路径,直到找到图像 URL.
config/environments/production.rb
Paperclip::Attachment.default_options[:s3_credentials] = {
:bucket => ENV['S3_BUCKET_NAME'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
:region => 'us-east-1'
}
Paperclip::Attachment.default_options[:s3_region] = 'us-east-1'
Paperclip::Attachment.default_options[:s3_host_name] = 's3.amazonaws.com'
Paperclip.options[:command_path] = 'usr/local/bin'
我一直在努力让 Paperclip 将图像上传到 Amazon S3。虽然我一开始让程序运行,但它只会在本地保存(尽管存储方法设置为 s3),一旦我发现我需要覆盖默认路径,它就会因写入错误而崩溃。
我不知道它是否重要,但我正在使用 Devise 并将 profile_image
添加到用户模型。
我正在尝试关注 Herokuthis guide
这是第一个只在本地写入的设置,尽管似乎是为 S3 设置的:
user.rb
class User < ApplicationRecord
has_attached_file :profile_image, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
validates_attachment_content_type :profile_image, :content_type => /\Aimage\/.*\Z/
end
production.rb 和 development.rb
config.paperlip_defaults = {
storage: :s3,
s3_credientials: {
bucket: ENV.fetch('S3_BUCKET_NAME'),
access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
s3_region: ENV.fetch('AWS_REGION')
}
}
Paperclip.options[:command_path] = '/usr/local/bin/'
上传表格的一部分 app/views/devise/registrations/edit.html.erb
<div class="form-group">
<% if @user.profile_image.present? %>
<%= image_tag(current_user.profile_image.url(:square)) %><br />
<%= link_to 'Remove profile image', remove_profile_image_path, method: :put, data: { confirm: 'Are you sure?' }, type: 'button' %>
<% else %>
<%= f.label :profile_image %>
<%= f.file_field :profile_image %>
<% end %>
</div>
使用此设置,Paperclip 可以工作,但它只会在本地保存图像(这在开发中和部署在 Heroku 上都是如此)。
接下来,我试图通过将此添加到
来强制显示 URL 来自 AWSconfig/initializers/paperclip.rb
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename'
这确实强制图像路径来自那里(当我为已经附加图像的用户刷新页面时,它被破坏了,因为没有上传图像)。但是,我删除了这张图片后,就无法再上传了。每次我尝试上传时都会收到此错误:
Errno::EACCES in Devise::RegistrationsController#update
Permission denied @ dir_s_mkdir - /users/profile_images
为了解决这个问题,我添加了一个额外的初始化程序(来自 Heroku 教程)
Paperclip::Attachment.default_options[:s3_host_name] = 's3-us-east-1.amazonaws.com'
不起作用,我尝试向 production.rb 和 development.rb 添加一行但没有成功(我尝试将两者都添加到默认散列和凭据散列)
s3_domain_url: 's3-us-east-1.amazonaws.com'
我知道这个错误是本地写错误,但是我的具体问题(除了如何做这个工作):
为什么Paperclip会忽略默认值中的存储值并保存在本地(在第一种情况下)? 为什么它试图写入我的本地磁盘(在第二种情况下)而不是上传到 S3?
更新 宝石文件
source 'https://rubygems.org'
ruby '2.3.3'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
gem 'puma', '~> 3.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'jquery-rails'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'bcrypt', '~> 3.1.7'
gem 'devise'
gem 'font-awesome-rails'
gem 'bourbon', '5.0.0.beta.7'
gem 'neat', '2.0.0'
gem 'autoprefixer-rails'
gem 'font-awesome-sass', '~> 4.7.0'
gem 'paperclip'
gem 'aws-sdk', '~> 2.3'
group :development, :test do
gem 'sqlite3'
gem 'byebug', platform: :mri
gem 'dotenv-rails'
end
group :development do
gem 'listen', '~> 3.0.5'
gem 'web-console'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'rubocop', require: false
gem 'haml-lint', require: false
end
group :test do
gem 'guard', '2.13.0'
gem 'minitest-reporters', '1.1.9'
gem 'coveralls', require: false
gem 'capybara'
gem 'factory_girl_rails', '~>4.0'
end
group :production do
gem 'pg', '0.18.4'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
您可能需要更改路径选项
PaperClip::Attachment.default_options[:path] = ":rails_root/public/system/.../the/rest/of/the/desired/path"
问题中的设置方式和使用的文档错误或对 Heroku 上的 Paperclip ~> 5.1
& AWS-SDK ~> 2.0
不再有效。
还有第二个未说明的问题,一旦它在开发中起作用就会变得明显,开发上传将覆盖生产上传,反之亦然。
这是对我有用的设置,使用同时上传到 S3 的开发环境和生产环境。
- 将初始化程序精简为仅共享信息
config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:path] = ':class/:attachment/:id_partition/:style/:filename'
Paperclip::Attachment.default_options[:storage] = :s3
Paperclip::Attachment.default_options[:s3_protocol] = 'https'
- 在用户模型中定义和有效图像和图像尺寸
app/model/users.rb
has_attached_file :profile_image, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
validates_attachment_content_type :profile_image, :content_type => /\Aimage\/.*\Z/
- 注册第二个开发映像存储桶并将必要的变量添加到 .ENV 文件
.ENV
# Shared S3 variables
AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXX
# Development variables
DEV_S3_BUCKET_NAME=your-dev-bucket-name
# Production variables
S3_BUCKET_NAME=your-production-bucket-name
- 将默认选项和命令路径放入各自的环境文件中
config/environments/development.rb
Paperclip::Attachment.default_options[:s3_credentials] = {
:bucket => ENV['DEV_S3_BUCKET_NAME'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
:region => 'us-east-2'
}
Paperclip::Attachment.default_options[:s3_region] = 'us-east-2'
Paperclip::Attachment.default_options[:s3_host_name] = 's3.us-east-2.amazonaws.com'
Paperclip.options[:command_path] = 'usr/local/bin'
在我的例子中,我对区域和主机名进行了硬编码,如果需要,您可以提取它们。我还选择在不同的区域托管开发映像,只是为了更加分离。另请注意,我创建的第一个存储桶(生产)不会将区域附加到地址。我不确定为什么 S3 是这样配置的,但是您可以通过上传图像然后在 AWS 控制台的文件夹中向下钻取来检查您的特定图像路径,直到找到图像 URL.
config/environments/production.rb
Paperclip::Attachment.default_options[:s3_credentials] = {
:bucket => ENV['S3_BUCKET_NAME'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'],
:region => 'us-east-1'
}
Paperclip::Attachment.default_options[:s3_region] = 'us-east-1'
Paperclip::Attachment.default_options[:s3_host_name] = 's3.amazonaws.com'
Paperclip.options[:command_path] = 'usr/local/bin'