Rails 6张图片上传到digitalocean spaces

Rails 6 image upload to digitalocean spaces

我有一个上传横幅和缩略图的博客。我最初将它设置为使用 carrierwave gem 上传到本地目录,并且我想尝试使用 digitalocean 空间,因为该应用程序已部署到 digitalocean 应用程序平台。我能够让它在 localhost:3000 上工作,但是当我将它部署到 digitalocean 时,它会一直恢复到之前的部署状态,说健康检查失败但不是真正的错误。

我决定将它部署到 heroku,因为我能够得到实际的错误。这是我从 heroku 得到的当前错误:

2021-03-09T22:41:10.466080+00:00 heroku[web.1]: Starting process with command `bin/rails server -p ${PORT:-5000} -e production`
2021-03-09T22:41:20.121636+00:00 app[web.1]: => Booting Puma
2021-03-09T22:41:20.121679+00:00 app[web.1]: => Rails 6.1.3 application starting in production
2021-03-09T22:41:20.121679+00:00 app[web.1]: => Run `bin/rails server --help` for more startup options
2021-03-09T22:41:31.105804+00:00 app[web.1]: [fog][WARNING] Unable to fetch credentials: Connection refused - connect(2) for 169.254.169.254:80 (Errno::ECONNREFUSED)
2021-03-09T22:41:31.108732+00:00 app[web.1]: Exiting
2021-03-09T22:41:31.110380+00:00 app[web.1]: /app/vendor/bundle/ruby/3.0.0/gems/fog-core-2.2.3/lib/fog/core/service.rb:244:in `validate_options': Missing required arguments: aws_access_key_id, aws_secret_access_key (ArgumentError)
2021-03-09T22:41:31.110386+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/fog-core-2.2.3/lib/fog/core/service.rb:268:in `handle_settings'
2021-03-09T22:41:31.110391+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/fog-core-2.2.3/lib/fog/core/service.rb:98:in `new'
2021-03-09T22:41:31.110426+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/fog-core-2.2.3/lib/fog/core/services_mixin.rb:30:in `new'
2021-03-09T22:41:31.110427+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.0/lib/carrierwave/storage/fog.rb:68:in `eager_load'
2021-03-09T22:41:31.110431+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.0/lib/carrierwave.rb:77:in `block in <class:Railtie>'
2021-03-09T22:41:31.110435+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/lazy_load_hooks.rb:68:in `block in execute_hook'
2021-03-09T22:41:31.110467+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/lazy_load_hooks.rb:61:in `with_execution_control'
2021-03-09T22:41:31.110472+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/lazy_load_hooks.rb:66:in `execute_hook'
2021-03-09T22:41:31.110473+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/lazy_load_hooks.rb:52:in `block in run_load_hooks'
2021-03-09T22:41:31.110508+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/lazy_load_hooks.rb:51:in `each'
2021-03-09T22:41:31.111096+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/lazy_load_hooks.rb:51:in `run_load_hooks'
2021-03-09T22:41:31.111100+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/application/finisher.rb:129:in `block in <module:Finisher>'
2021-03-09T22:41:31.111101+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/initializable.rb:32:in `instance_exec'
2021-03-09T22:41:31.111127+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/initializable.rb:32:in `run'
2021-03-09T22:41:31.111132+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/initializable.rb:61:in `block in run_initializers'
2021-03-09T22:41:31.111132+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:228:in `block in tsort_each'
2021-03-09T22:41:31.111164+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
2021-03-09T22:41:31.111168+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:431:in `each_strongly_connected_component_from'
2021-03-09T22:41:31.111169+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:349:in `block in each_strongly_connected_component'
2021-03-09T22:41:31.111201+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:347:in `each'
2021-03-09T22:41:31.111202+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:347:in `call'
2021-03-09T22:41:31.111772+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:347:in `each_strongly_connected_component'
2021-03-09T22:41:31.111777+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:226:in `tsort_each'
2021-03-09T22:41:31.111777+00:00 app[web.1]: from /app/vendor/ruby-3.0.0/lib/ruby/3.0.0/tsort.rb:205:in `tsort_each'
2021-03-09T22:41:31.111781+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/initializable.rb:60:in `run_initializers'
2021-03-09T22:41:31.111808+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/application.rb:384:in `initialize!'
2021-03-09T22:41:31.111809+00:00 app[web.1]: from /app/config/environment.rb:5:in `<main>'
2021-03-09T22:41:31.111813+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
2021-03-09T22:41:31.111839+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
2021-03-09T22:41:31.111844+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
2021-03-09T22:41:31.111844+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
2021-03-09T22:41:31.111845+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
2021-03-09T22:41:31.111845+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:34:in `require'
2021-03-09T22:41:31.111848+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/dependencies.rb:332:in `block in require'
2021-03-09T22:41:31.111851+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/dependencies.rb:299:in `load_dependency'
2021-03-09T22:41:31.111884+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/activesupport-6.1.3/lib/active_support/dependencies.rb:332:in `require'
2021-03-09T22:41:31.112296+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:53:in `require_relative'
2021-03-09T22:41:31.112301+00:00 app[web.1]: from config.ru:3:in `block in <main>'
2021-03-09T22:41:31.112302+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/builder.rb:116:in `eval'
2021-03-09T22:41:31.112334+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/builder.rb:116:in `new_from_string'
2021-03-09T22:41:31.112339+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/builder.rb:105:in `load_file'
2021-03-09T22:41:31.112340+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/builder.rb:66:in `parse_file'
2021-03-09T22:41:31.112367+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/server.rb:349:in `build_app_and_options_from_config'
2021-03-09T22:41:31.112368+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/server.rb:249:in `app'
2021-03-09T22:41:31.112372+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/server.rb:422:in `wrapped_app'
2021-03-09T22:41:31.112398+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/server.rb:312:in `block in start'
2021-03-09T22:41:31.112403+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/server.rb:379:in `handle_profiling'
2021-03-09T22:41:31.112809+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/rack-2.2.3/lib/rack/server.rb:311:in `start'
2021-03-09T22:41:31.112813+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/commands/server/server_command.rb:39:in `start'
2021-03-09T22:41:31.112841+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/commands/server/server_command.rb:144:in `block in perform'
2021-03-09T22:41:31.112845+00:00 app[web.1]: from <internal:kernel>:90:in `tap'
2021-03-09T22:41:31.112846+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/commands/server/server_command.rb:135:in `perform'
2021-03-09T22:41:31.112877+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
2021-03-09T22:41:31.112881+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
2021-03-09T22:41:31.112882+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
2021-03-09T22:41:31.112912+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/command/base.rb:69:in `perform'
2021-03-09T22:41:31.114191+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/command.rb:50:in `invoke'
2021-03-09T22:41:31.114195+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/railties-6.1.3/lib/rails/commands.rb:18:in `<main>'
2021-03-09T22:41:31.114196+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
2021-03-09T22:41:31.114229+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
2021-03-09T22:41:31.114234+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
2021-03-09T22:41:31.114234+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
2021-03-09T22:41:31.114261+00:00 app[web.1]: from /app/vendor/bundle/ruby/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
2021-03-09T22:41:31.114262+00:00 app[web.1]: from bin/rails:5:in `<main>'
2021-03-09T22:41:31.238223+00:00 heroku[web.1]: Process exited with status 1
2021-03-09T22:41:31.311694+00:00 heroku[web.1]: State changed from starting to crashed

服务器启动后崩溃,提示 fog 无法获取凭据。

这是我的 initializer/carrierwave.rb 文件:

CarrierWave.configure do |config|
  config.fog_credentials = {
    provider:              'AWS',                        # required
    aws_access_key_id:     Rails.application.credentials.aws(:digitalocean_spaces_key),                        # required unless using use_iam_profile
    aws_secret_access_key: Rails.application.credentials.aws(:digitalocean_spaces_secret),                        # required unless using use_iam_profile
    use_iam_profile:       true,                         # optional, defaults to false
    region:                'nyc3',                  # optional, defaults to 'us-east-1'
    host:                  'nyc3.digitaloceanspaces.com',             # optional, defaults to nil
    endpoint:              'https://nyc3.digitaloceanspaces.com' # optional, defaults to nil
  }


  config.fog_directory  = 'judo'                                      # required
  config.fog_public     = true                                                 # optional, defaults to true
  #config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } # optional, defaults to {}
  # For an application which utilizes multiple servers but does not need caches persisted across requests,
  # uncomment the line :file instead of the default :storage.  Otherwise, it will use AWS as the temp cache store.
  # config.cache_storage = :file
end

这是对 carrierwave.rb 文件的另一种尝试:

CarrierWave.configure do |config|
  config.fog_credentials = {
    provider:              'AWS',                        # required
    digitalocean_spaces_key_id:     Rails.application.credentials.digitalocean_spaces_key,                        # required unless using use_iam_profile
    digitalocean_spaces_secret: Rails.application.credentials.digitalocean_spaces_secret,
    digitalocean_spaces_bucket: Rails.application.credentials.digitalocean_spaces_bucket,
    use_iam_profile:       true,                         # optional, defaults to false
    region:                'nyc3',                  # optional, defaults to 'us-east-1'
    host:                  'nyc3.digitaloceanspaces.com',             # optional, defaults to nil
    endpoint:              'https://nyc3.digitaloceanspaces.com' # optional, defaults to nil
  }


  config.fog_directory  = 'judo'                                      # required
  config.fog_public     = true                                                 # optional, defaults to true
  #config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } # optional, defaults to {}
  # For an application which utilizes multiple servers but does not need caches persisted across requests,
  # uncomment the line :file instead of the default :storage.  Otherwise, it will use AWS as the temp cache store.
  # config.cache_storage = :file
end

这是我的 credentials.yml 文件:

production:
  digitalocean_spaces_key: <%= ENV["DIGITALOCEAN_SPACES_KEY"] %>
  digitalocean_spaces_secret: <%= ENV["DIGITALOCEAN_SPACES_SECRET"] %>
  digitalocean_spaces_bucket: <%= ENV["DIGITALOCEAN_SPACES_BUCKET"] %>

development:
  digitalocean_spaces_key: my_key
  digitalocean_spaces_secret: my_secret
  digitalocean_spaces_bucket: judo

我在 digitalocean 上的应用程序中输入了 spaces key、secret 和 bucket 作为应用程序级变量。

这是我的 uploaders/banner_uploader.rb 文件:

class BannerUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  #include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  # storage :file
  storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process scale: [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process resize_to_fit: [50, 50]
  # end

  # Add an allowlist of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_allowlist
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end
end

这是我的 post.rb:

class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, as: :commentable, dependent: :destroy
  # Active Storage from Rails 5
  #has_one_attached :thumbnail
  #has_one_attached :banner
  # Action Text from Rails 6
  has_rich_text :body
  
  mount_uploader :banner, BannerUploader
 
  validates :title, length: { minimum: 5 }
  validates :body,  length: { minimum: 25 }

  self.per_page = 10
  extend FriendlyId
  friendly_id :title, use: :slugged

end

这是我的 Gemfile:

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '3.0.0'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
gem 'rails', '~> 6.1.3'

# Use Puma as the app server
gem 'puma', '~> 5.0'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 5.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.4', require: false

group :development, :test do
  # Use sqlite3 as the database for Active Record
  gem 'sqlite3', '~> 1.4'
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 4.1.0'
  # Display performance information such as SQL time and flame graphs for each request in your browser.
  # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
  # gem 'rack-mini-profiler', '~> 2.0'
  gem 'listen', '~> 3.3'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
end

group :production do 
  gem 'pg'
end 

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 3.26'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'devise'
gem 'simple_form'
gem 'faker'
gem 'will_paginate'
gem 'friendly_id'
gem "carrierwave"
gem "mime-types"
gem "fog-aws"

服务器似乎无法访问 credentials.yml 的内容。此文件已加密,Rails 使用存储在 master.key 文件中的主密钥来读取它。因此,鉴于 master.key 未签入版本控制,您需要在服务器上手动提供它。请查看这篇文章https://medium.com/cedarcode/rails-5-2-credentials-9b3324851336

本节:

Deploying master key

When you move your code to a server, you need to make sure that your config/credentials.yml.enc file can be decrypted. That means that somehow you’ll need to provide Rails with your master key, given that it is not checked into version control.

There are two ways of doing that:

Option 1: Place the config/master.key file in the server. You’ll normally want to symlink this file to a shared folder in the server filesystem. Again, do not version your config/master.key file.

Option 2: create a RAILS_MASTER_KEY ENV variable. Rails will detect it and use it as your master key, e.g. in heroku: heroku config:set RAILS_MASTER_KEY=.

You should be able to use any of those indistinctly.

如果您使用 RBENV 作为您的 ruby 经理,您可以存储您的环境变量:

您将在您的项目文件夹中创建 .rbenv-vars,而不是您的 rails 项目文件夹,而是您的项目文件夹所在的文件夹,如果需要,也可以是父文件夹。

之后你将环境变量放入文件中,如下所示:

DATABASE_PWD=*****

没有引号,在“=”

之前或之后也没有 space

有关更多信息,请查看此 link 继续Rails:https://gorails.com/deploy/ubuntu/18.04#capistrano

希望对您有所帮助