開発者ドキュメント

DigitalOceanSpacesを使用してRails6でActiveStorageを使用する方法

序章

ユーザーがファイルをアップロードして保存できるWebアプリケーションを構築する場合は、スケーラブルなファイルストレージソリューションを使用する必要があります。 これにより、アプリケーションの人気が非常に高くなった場合でも、スペースが不足する危険がなくなります。 結局のところ、これらのアップロードは、プロフィール写真から家の写真、PDFレポートまで何でもかまいません。 また、ファイルストレージソリューションの信頼性を高めて、重要な顧客ファイルを失わないようにし、訪問者がファイルの転送を待たないようにする必要があります。 これもすべて手頃な価格にしたいと思います。

DigitalOcean Spaces は、これらすべてのニーズに対応できます。 AmazonのS3サービスと互換性があるため、Rails6に付属する新しいActiveStorage ライブラリを使用して、RubyonRailsアプリケーションにすばやく統合できます。

このガイドでは、Railsアプリケーションを構成して、DigitalOceanSpacesでActiveStorageを使用するようにします。 次に、直接アップロードとSpacesの組み込みCDN(コンテンツ配信ネットワーク)を使用して、アップロードとダウンロードを高速に取得するために必要な構成を実行します。

終了すると、ファイルストレージとDigitalOceanスペースを独自のRailsアプリケーションに統合する準備が整います。

前提条件

このガイドを開始する前に、次のものが必要です。

ステップ1—サンプルアプリを実行する

完全なRailsアプリケーションを最初から構築するのではなく、ActiveStorageを使用する既存のRails 6アプリケーションのクローンを作成し、それを変更して、イメージストレージバックエンドとしてDigitalOceanSpacesを使用します。 使用するアプリはSpacePuppies です。これは、お気に入りの子犬の写真をアップロードして表示できる画像ギャラリーです。 アプリケーションは次の図のようになります。

ターミナルを開き、次のコマンドを使用してGitHubからアプリケーションのクローンを作成します。

  1. git clone https://github.com/do-community/space-puppies

次のような出力が表示されます。

Output
Cloning into 'space-puppies'... remote: Enumerating objects: 122, done. remote: Counting objects: 100% (122/122), done. remote: Compressing objects: 100% (103/103), done. remote: Total 122 (delta 3), reused 122 (delta 3), pack-reused 0 Receiving objects: 100% (122/122), 163.17 KiB | 1018.00 KiB/s, done. Resolving deltas: 100% (3/3), done.

次に、Rubyのバージョンを確認します。 SpacePuppiesはRuby2.7.1を使用しているため、 rbenv versions インストールしたバージョンを確認するには:

  1. rbenv versions

前提条件のチュートリアルに従っている場合、そのリストにはRuby 2.5.1しか含まれておらず、出力は次のようになります。

Output
* system 2.5.1

そのリストにRuby2.7.1が含まれていない場合は、を使用してインストールしてください ruby-build:

  1. rbenv install 2.7.1

お使いのマシンの速度とオペレーティングシステムによっては、これには時間がかかる場合があります。 次のような出力が表示されます。

Output
Downloading ruby-2.7.1.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.1.tar.bz2 Installing ruby-2.7.1... Installed ruby-2.7.1 to /root/.rbenv/versions/2.7.1

に変更します space-puppies ディレクトリ:

  1. cd space-puppies

rbenv ディレクトリに入ると、Rubyのバージョンが自動的に変更されます。 バージョンを確認します。

  1. ruby --version

次のような出力が表示されます。

Output
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]

次に、アプリの実行に必要なRubygemsとJavaScriptパッケージをインストールします。 次に、SpacePuppiesアプリを実行するために必要なデータベースの移行を行います。

を使用して必要なすべての宝石をインストールします bundle 指図:

  1. bundle install

次に、伝えるために rbenv Bundlerによってインストールされた新しいバイナリについては、 rehash 指図:

  1. rbenv rehash

次に、教えて yarn 必要なJavaScript依存関係をインストールするには:

  1. yarn install

次に、Railsの組み込み移行ツールを使用してデータベーススキーマを作成します。

  1. rails db:migrate

すべてのライブラリがインストールされ、データベースが作成されたら、次のコマンドを使用して組み込みのWebサーバーを起動します。

  1. rails s

注:デフォルトでは、 rails s ローカルループバックアドレスにのみバインドします。つまり、コマンドを実行するのと同じコンピューターからのみサーバーにアクセスできます。 ドロップレットで実行していて、ローカルマシンで実行されているブラウザからサーバーにアクセスする場合は、Railsサーバーにバインドしてリモートリクエストに応答するように指示する必要があります。 0.0.0.0. あなたはこのコマンドでそれをすることができます:

  1. rails s -b 0.0.0.0

サーバーが起動し、次のような出力が表示されます。

Output
=> Booting Puma => Rails 6.0.3.2 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 4.3.5 (ruby 2.7.1-p83), codename: Mysterious Traveller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://127.0.0.1:3000 * Listening on tcp://[::1]:3000 Use Ctrl-C to stop

これで、Webブラウザでアプリケーションにアクセスできます。 ローカルマシンでアプリケーションを実行している場合は、次の場所に移動します。 http://localhost:3000. ドロップレットまたはその他のリモートサーバーで実行している場合は、次の場所に移動します http://your_server_ip:3000.

アプリのインターフェースが表示されますが、今回は子犬がいません。 New Puppy ボタンをクリックして、画像をいくつか追加してみてください。

テストに使用する子犬の写真が必要な場合は、Unsplashにテストに使用できる広範なリストがあります。 プロジェクトでこれらのイメージを使用する場合は、Unsplashライセンスを確認してください。

先に進む前に、アプリケーションの各レイヤーを見ていき、ActiveStorageが各部分でどのように機能するかを見て、DigitalOceanSpacesに必要な変更を加えることができるようにします。 ActiveStorageの詳細については、Railsの公式ドキュメントの Active StorageOverviewページを参照してください。

まず、データベースに保存しているアプリケーション内のオブジェクトを表すモデルを確認します。 あなたは見つけるでしょう Puppy のモデル app/models/puppy.rb. このファイルをテキストエディタで開くと、次のコードが表示されます。

app / models / puppy.rb
class Puppy < ApplicationRecord

  has_one_attached :photo

end

あなたは見つけるでしょう has_one_attached モデル内のマクロ。それぞれに写真が添付されていることを示します Puppy モデルインスタンス。 これらの写真は次のように保存されます ActiveStorage::Blob 経由のインスタンス ActiveStorage::Attached::One プロキシー。

このファイルを閉じます。

スタックの次の層はコントローラーです。 Railsアプリケーションでは、コントローラーはデータベースモデルへのアクセスを制御し、ユーザーからの要求に応答する責任があります。 対応するコントローラー Puppy モデルは PuppiesController あなたが見つけるでしょう app/controllers/puppies_controller.rb. このファイルをエディターで開くと、次のコードが表示されます。

app / controllers / puppies_controller.rb
class PuppiesController < ApplicationController

  def index
    @puppies = Puppy.with_attached_photo
  end

  # ... snipped other actions ...

end

ファイル内のすべては、 with_attached_photo 電話。 この呼び出しにより、ActiveRecordは関連するすべてをロードします ActiveStorage::Blob のリストを取得するときの関連付け Puppy モデル。 これは、ActiveStorageが提供するスコープであり、高価な N+1データベースクエリを回避するのに役立ちます。

最後に、アプリケーションがユーザーのブラウザーに送信するHTMLを生成するビューを見てみましょう。 このアプリにはいくつかのビューがありますが、アップロードされた子犬の画像を表示するためのビューに焦点を当てる必要があります。 このファイルは次の場所にあります。 app/views/puppies/_puppy.html.erb. エディターで開くと、次のようなコードが表示されます。

app / views / puppies / _puppy.html.erb
<div class="puppy">
  <%= image_tag puppy.photo.variant(resize_to_fill: [250, 250]) %>
</div>

ActiveStorageはRailsと連携するように設計されているため、組み込みのを使用できます image_tag 写真が保存されている場所に関係なく、添付された写真を指すURLを生成するヘルパー。 この場合、アプリは画像にバリアントサポートを使用しています。 ユーザーが最初にこのバリアントをリクエストすると、ActiveStorageは image_processing gemを介してImageMagickを自動的に使用し、要件に合った変更された画像を生成します。 この場合、250×250ピクセルのボックスを埋める子犬の写真が作成されます。 バリアントは元の写真と同じ場所に保存されます。つまり、各バリアントを生成する必要があるのは1回だけです。 Railsは、後続のリクエストで生成されたバージョンを提供します。

注:画像のバリエーションの生成は遅くなる可能性があり、ユーザーを待たせたくない場合があります。 特定のバリアントが必要になることがわかっている場合は、 .processed 方法:

puppy.photo.variant(resize_to_fill: [250, 250]).processed

本番環境にデプロイするときは、この種の処理をバックグラウンドジョブで実行することをお勧めします。 アクティブジョブを調べて、呼び出すタスクを作成します processed 事前に画像を生成します。

これで、アプリケーションがローカルで実行され、すべてのコード部分がどのように組み合わされるかがわかります。 次に、アップロードをクラウドに移動できるように、新しいDigitalOceanSpaceをセットアップします。

ステップ2—DigitalOceanスペースを設定する

現時点では、Space Puppiesアプリケーションは画像をローカルに保存します。これは開発やテストには問題ありませんが、本番環境でこのモードを使用することはほぼ間違いありません。 アプリケーションサーバーインスタンスを追加してアプリケーションを水平方向にスケーリングするには、すべてのサーバーに各イメージのコピーが必要です。

このステップでは、アプリの画像に使用するDigitalOceanスペースを作成します。

DigitalOcean管理コンソールにサインインし、右上の作成をクリックして、スペースを選択します。

データセンターを選択し、CDNを今のところ無効のままにします。 後でこれに戻ります。 ファイルリストがファイルリストの制限に設定されていることを確認します。

スペースの名前を選択してください。 これはすべてのSpacesユーザー間で一意である必要があるため、次のような一意の名前を選択してください。 yourname-space-puppies. スペースの作成をクリックします。

警告:顧客に代わって保存するファイルへのアクセスに注意してください。 ファイルストレージの設定ミスによるデータ漏洩やハッキングの例が数多くあります。 デフォルトでは、ActiveStorageファイルにアクセスできるのは、認証されたURLを生成した場合のみですが、顧客データを扱う場合は注意が必要です。

次に、新しいスペースが表示されます。

設定タブをクリックして、スペースのエンドポイントをメモします。 Railsアプリケーションを構成するときに必要になります。

次に、このスペースにActiveStorageファイルを保存するようにRailsアプリケーションを構成します。 これを安全に行うには、新しいSpacesアクセスキーとシークレットを作成する必要があります。

左側のナビゲーションでAPIをクリックし、右下の新しいキーの生成をクリックします。 新しいキーに「DevelopmentMachine」のようなわかりやすい名前を付けます。 あなたの秘密は一度だけ現れるので、しばらくの間安全な場所にそれをコピーすることを忘れないでください。

Railsアプリでは、そのアクセストークンを安全に保存する方法が必要になるため、Railsの安全な資格情報管理機能を使用します。 資格情報を編集するには、端末で次のコマンドを実行します。

  1. EDITOR="nano -w" rails credentials:edit

これによりマスターキーが生成され、 nano 値を編集できるようにエディター。

nano、以下を追加します credentials.yml DigitalOceanのAPIキーとシークレットを使用したファイル:

config / credentials.yml
digitalocean:
  access_key: YOUR_API_ACCESS_KEY
  secret: YOUR_API_ACCESS_SCRET

ファイルを保存して閉じます(Ctrl+X、 それから Y、 それから Enter)、およびRailsは、ソース管理に安全にコミットできる暗号化されたバージョンを保存します。 config/credentials.yml.enc.

次のような出力が表示されます。

Output
Adding config/master.key to store the encryption key: RANDOM_HASH_HERE Save this in a password manager your team can access. If you lose the key, no one, including you, can access anything encrypted with it. create config/master.key File encrypted and saved.

クレデンシャルを構成したので、アプリを新しいSpacesバケットにポイントする準備が整いました。

ファイルを開く config/storage.yml エディターで、そのファイルの最後に次の定義を追加します。

config / storage.yml
digitalocean:
  service: S3
  endpoint: https://your-spaces-endpoint-here
  access_key_id: <%= Rails.application.credentials.dig(:digitalocean, :access_key) %>
  secret_access_key: <%= Rails.application.credentials.dig(:digitalocean, :secret) %>
  bucket: your-space-name-here
  region: unused

サービスが言うことに注意してください S3 それよりも Spaces. SpacesにはS3互換のAPIがあり、RailsはS3をネイティブにサポートしています。 あなたのエンドポイントは https:// 続いて、前にコピーしたスペースのエンドポイント、および bucket nameは、スペースの作成時に入力したスペースの名前です。 スペースを表示すると、コントロールパネルにバケット名もタイトルとして表示されます。

この構成ファイルは暗号化されずに保存されるため、アクセスキーとシークレットを入力する代わりに、安全に入力したものを参照します。 credentials.yml.enc.

:DigitalOceanは、エンドポイントを使用してリージョンを指定します。 ただし、リージョンを指定する必要があります。指定しないと、ActiveStorageが文句を言います。 DigitalOceanはそれを無視するので、好きな値に設定できます。 値 unused サンプルコードでは、使用していないことが明確になっています。

構成ファイルを保存します。

次に、ローカルファイルシステムではなく、ファイルストレージバックエンドにSpacesを使用するようにRailsに指示する必要があります。 開ける config/environments/development.rb エディターで変更します config.active_storage.service からのエントリ :local::digitalocean:

config / environment / development.rb

  # ...

  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :digitalocean

  # ... 

ファイルを保存して、エディターを終了します。 サーバーを再起動します。

  1. rails s -b 0.0.0.0

訪問 http://localhost:3000 また http://your server ip:3000 もう一度ブラウザで。

いくつかの画像をアップロードすると、アプリはそれらをDigitalOceanSpaceに保存します。 これは、DigitalOceanコンソールでスペースにアクセスすると確認できます。 アップロードされたファイルとバリアントが一覧表示されます。

ActiveStorageはデフォルトでランダムなファイル名を使用します。これは、アップロードされた顧客データを保護する場合に役立ちます。 代わりに、元のファイル名を含むメタデータがデータベースに保存されます。

注: Aws::S3::Errors::SignatureDoesNotMatch、それはあなたの資格情報が正しくないことを意味するかもしれません。 走る rails credentials:edit もう一度、それらを再確認してください。

Railsは、ファイルの名前とメタデータを次のように保存します。 ActiveStorage::Blob 記録。 あなたはアクセスすることができます ActiveStorage::Blob 添付ファイルにちなんで名付けられたアクセサメソッドを呼び出すことにより、任意のレコードに対して。 この場合、添付ファイルは photo.

やってみよう。 ターミナルでRailsコンソールを起動します。

  1. rails c

アップロードした最後の子犬の写真からブロブを取得します。

> Puppy.last.photo.blob
#=> => #<ActiveStorage::Blob ...>

これで、アップロードをスケーラブルで信頼性が高く、手頃な価格のオブジェクトストアに保存するRailsアプリケーションができました。

次の2つのステップでは、このソリューションのパフォーマンスとユーザーの速度を向上させるのに役立つ、アプリに追加できる2つのオプションについて説明します。

ステップ3— Spaces CDNの設定(オプション)

注:この手順では、DigitalOceanを指すネームサーバーを備えたドーマンが必要です。 ドメインの追加方法ガイドに従ってください。

コンテンツ配信ネットワーク(CDN)を使用すると、ファイルのコピーをユーザーの近くに配置することで、ユーザーがファイルをより高速にダウンロードできるようになります。

Uptrends CDN PerformanceCheckなどのツールを使用してCDNパフォーマンスを調査できます。 前の手順でアップロードした写真のいずれかのURLを追加すると、近くにいる場合は高速であることがわかりますが、地理的に離れるにつれて状況は少し遅くなります。 ブラウザの開発ツールを使用するか、Railsコンソールを起動してURLを取得できます(rails c)と呼び出し service_url 添付ファイルに。

> Puppy.last.photo.service_url

これは、サンフランシスコのデータセンターにあるファイルを使用した上昇傾向レポートの例です。 サンフランシスコからの距離に応じて時間が減少することに注意してください。 サンディエゴの時間は短いですが、パリの時間ははるかに長いです。

Spacesの組み込みCDNを有効にすることで、速度を向上させることができます。 DigitalOceanコントロールパネルのSpacesに移動し、手順2で作成したスペースの名前をクリックします。 次に、設定タブを選択し、 CDN(コンテンツ配信ネットワーク)の横にある編集をクリックしてから、CDNを有効にするをクリックします。

次に、CDNに使用するドメインを選択し、そのドメインのSSL証明書を作成する必要があります。 これは、 Let’sEncryptを使用して自動的に行うことができます。 [カスタムサブドメインを使用する]ドロップダウンをクリックしてから、新しいサブドメイン証明書を追加するをクリックします。

使用するドメインを見つけて、サブドメインを作成するオプションを選択します。 何かのようなもの cdn.yourdomain.com 標準の命名規則です。 次に、証明書に名前を付けて、[証明書を生成してサブドメインを使用する]ボタンをクリックします。

CDN(コンテンツ配信ネットワーク)の下にある保存ボタンを押します。

これでCDNが有効になりましたが、RailsアプリケーションにCDNを使用するように指示する必要があります。 これは、このバージョンのRailsではActiveStorageに組み込まれていないため、いくつかの組み込みRailsフレームワークメソッドをオーバーライドして機能させます。

と呼ばれる新しいRails初期化子を作成します config/initializers/active_storage_cdn.rb URLを書き換える次のコードを追加します。

config / initializers / active_storage_cdn.rb
Rails.application.config.after_initialize do
  require "active_storage/service/s3_service"

  module SimpleCDNUrlReplacement
    CDN_HOST = "cdn.yourdomain.com"
  
    def url(...)
      url = super
      original_host = "#{bucket.name}.#{client.client.config.endpoint.host}"      
      url.gsub(original_host, CDN_HOST)
    end
  end

  ActiveStorage::Service::S3Service.prepend(SimpleCDNUrlReplacement)
end

この初期化子は、アプリケーションがからURLを要求するたびに実行されます。 ActiveStorage::Service::S3Service プロバイダー。 次に、元の非CDNホストを、次のように定義されたCDNホストに置き換えます。 CDN_HOST 絶え間ない。

これでサーバーを再起動できます。各写真がCDNからのものであることがわかります。 スペースを設定したデータセンターからエッジノードにコンテンツを転送するのはDigitalOceanが処理するため、これらを再アップロードする必要はありません。

Uptrendsのパフォーマンスチェックサイトで写真にアクセスする速度を、CDN以前の速度と比較することをお勧めします。 サンフランシスコを拠点とするスペースでCDNを使用する例を次に示します。 グローバルな速度が大幅に向上していることがわかります。

次に、ブラウザから直接ファイルを受信するようにアプリケーションを構成します。

ステップ4—直接アップロードの設定(オプション)

検討したいActiveStorageの最後の機能は直接アップロードと呼ばれます。 これで、ユーザーがファイルをアップロードすると、データがサーバーに送信され、Railsによって処理されてから、Spaceに転送されます。 これは、多数の同時ユーザーがいる場合、またはユーザーが大きなファイルをアップロードしている場合に問題を引き起こす可能性があります。各ファイルは(ほとんどの場合)アップロードの全期間にわたって単一のアプリサーバースレッドを使用するためです。

対照的に、直接アップロードは、Railsサーバーホップを介さずにDigitalOceanSpaceに直接送信されます。 これを行うには、Railsに付属する組み込みのJavaScriptを有効にして、クロスオリジンリソースシェアリングを構成します([CORS](( https://developer.mozilla.org/en-US/docs/Webスペースの/HTTP/ CORS )。これにより、リクエストが別の場所から発信されている場合でも、リクエストをスペースに直接安全に送信できます。

まず、スペースのCORSを構成します。 使用します s3cmd これを行うには、 DigitalOceanSpacesを使用したs3cmd2.xのセットアップを実行できます(まだSpacesで動作するように構成していない場合)。

と呼ばれる新しいファイルを作成します cors.xml 次のコードをファイルに追加して、 your_domain 開発に使用しているドメインを使用します。 ローカルマシンで開発している場合は、 http://localhost:3000. ドロップレットで開発している場合、これはドロップレットのIPアドレスになります。

cors.xml
<CORSConfiguration>
 <CORSRule>
   <AllowedOrigin>your_domain</AllowedOrigin>
   <AllowedMethod>PUT</AllowedMethod>
   <AllowedHeader>*</AllowedHeader>
   <ExposeHeader>Origin</ExposeHeader>
   <ExposeHeader>Content-Type</ExposeHeader>
   <ExposeHeader>Content-MD5</ExposeHeader>
   <ExposeHeader>Content-Disposition</ExposeHeader>
   <MaxAgeSeconds>3600</MaxAgeSeconds>
 </CORSRule>
</CORSConfiguration>

その後、使用することができます s3cmd これをスペースのCORS構成として設定するには:

  1. s3cmd setcors cors.xml s3://your-space-name-here

このコマンドが正常に実行された場合、出力はありませんが、DigitalOceanコントロールパネルでスペースを確認することで、コマンドが機能したことを確認できます。 スペースを選択し、スペースの名前を選択してから、設定タブを選択します。 CORSConfigurationsの見出しの下に設定が表示されます。

注:現時点では、使用する必要があります s3cmd コントロールパネルではなく、「localhost」ドメインのCORSを構成します。これは、コントロールパネルがこれらを無効なドメインとして扱うためです。 ローカルホスト以外のドメイン(Droplet IPなど)を使用している場合は、ここで安全に実行できます。

次に、直接アップロードを使用するようにRailsに指示する必要があります。これは、 direct_upload オプション file_field ヘルパー。 開ける app/views/puppies/new.html.erb エディターで、 file_field ヘルパー:

app / views / puppies / new.html.erb
<h2>New Puppy</h2>

<%= form_with(model: @puppy) do |f| %>

  <div class="form-item">
    <%= f.label :photo %>
    <%= f.file_field :photo, accept: "image/*", direct_upload: true %>
  </div>

  <div class="form-item">
    <%= f.submit "Create puppy", class: "btn", data: { disable_with: "Creating..." } %>
  </div>

<% end %>

ファイルを保存して、サーバーを再起動します。

  1. rails s -b 0.0.0.0

新しい写真をアップロードすると、写真はDigitalOceanSpacesに直接アップロードされます。 これを確認するには、 PUT 子犬の作成ボタンをクリックしたときに行われるリクエスト。 ブラウザのWebコンソールを確認するか、Railsサーバーのログを読み取ることで、リクエストを見つけることができます。 特に大きな画像の場合、画像のアップロードが大幅に高速化されていることに気付くでしょう。

結論

この記事では、ActiveStorageを使用して基本的なRailsアプリケーションを変更し、DigitalOcean Spacesで安全、高速、スケーラブルなファイルを保存しました。 ユーザーがどこにいても高速ダウンロード用にCDNを構成し、アプリサーバーが圧倒されないように直接アップロードを実装しました。

これで、このコードと構成を取得して、独自のRailsアプリケーションに適合するように適合させることができます。

モバイルバージョンを終了