搭配 Ruby 使用 Cloud Storage

這部分的 Bookshelf 教學課程說明範例應用程式如何將圖片儲存在 Cloud Storage 中。

完整的教學課程內容涵蓋了數個頁面的篇幅,本頁面屬於其中一個單元。如要從頭開始並閱讀設定操作說明,請前往 Ruby Bookshelf 應用程式頁面。

建立 Cloud Storage 值區

Cloud Storage 可讓您儲存及提供二進位資料,值區是二進位物件的高階容器。

下列操作說明詳述如何建立 Cloud Storage 值區。值區是 Cloud Storage 中保存資料的基本容器。

  1. 在終端機視窗中,輸入以下指令:

    gsutil mb gs://[YOUR-BUCKET-NAME]

    [YOUR-BUCKET-NAME] 是 Cloud Storage 值區的名稱。

  2. 如要查看 Bookshelf 應用程式中的上傳圖片,請將值區的預設存取控制清單 (ACL) 設定為 public-read

    gsutil defacl set public-read gs://[YOUR-BUCKET-NAME]

安裝依附元件

前往 getting-started-ruby/3-cloud-storage 目錄,並輸入下列指令:

bundle install

設定

  1. 複製範例 settings 檔案:

    cp config/settings.example.yml config/settings.yml
    
  2. 開啟 settings.yml 進行編輯,將預留位置替換為您的專案和 Cloud Storage 值區名稱。

    例如,假設您的專案名稱是 my-project,值區名稱是 my-bucket。這樣您 settings.yml 檔案的 default 部分會如下所示:

    default: &default
      project_id: my-project
      gcs_bucket: my-bucket
    
  3. 複製範例 database 檔案:

    cp config/database.example.yml config/database.yml
    
  4. 將範例應用程式設為使用您在本教學課程的使用結構化資料部分中設定的資料庫:

    Cloud SQL

    • 編輯 database.yml,將檔案中屬於 Cloud SQL 的各行,取消註解。

       mysql_settings: &mysql_settings
         adapter: mysql2
         encoding: utf8
         pool: 5
         timeout: 5000
         username: [MYSQL_USER]
         password: [MYSQL_PASS]
         database: [MYSQL_DATABASE]
         socket: /cloudsql/[YOUR_INSTANCE_CONNECTION_NAME]
      
      • [MYSQL_USER][MYSQL_PASS] 改成您先前建立的 Cloud SQL 執行個體使用者名稱和密碼。

      • [MYSQL_DATABASE] 改成您先前建立的資料庫名稱。

      • [YOUR_INSTANCE_CONNECTION_NAME] 改成您 Cloud SQL 執行個體的 Instance Connection Name

    • 執行遷移作業。

      bundle exec rake db:migrate
      

    PostgreSQL

    • 編輯 database.yml,將檔案中屬於 PostgreSQL 的各行,取消註解;並將 your-postgresql-* 預留位置改成您的 PostgreSQL 執行個體和資料庫值。例如,假設您的 IPv4 位址為 173.194.230.44,使用者名稱為 postgres,密碼為 pword123,資料庫名稱為 bookshelf。那麼您 database.yml 檔案的 PostgreSQL 部分會如下所示:

      # PostgreSQL Sample Database Configuration
      # ----------------------------------------
        adapter: postgresql
        encoding: unicode
        pool: 5
        username: postgres
        password: pword123
        host: 173.194.230.44
        database: bookshelf
      
    • 建立所需的資料庫和資料表。

      bundle exec rake db:create
      bundle exec rake db:migrate
      

    Cloud Datastore

    • 編輯 database.yml,將檔案中屬於 Cloud Datastore 的各行,取消註解。將 your-project-id 改成您的 Google Cloud Platform 專案 ID。例如,假設您的專案 ID 是 my-project:那麼您 database.yml 檔案的 Cloud Datastore 部分會如下所示:

      # Google Cloud Datastore Sample Database Configuration
      # ----------------------------------------------------
      dataset_id: my-project
      
    • 執行 Rake 工作,為 Cloud Datastore 複製範例專案檔案。

      bundle exec rake backend:datastore
      

在本機電腦執行應用程式

  1. 啟動本機網路伺服器。

    bundle exec rails server
    
  2. 在網路瀏覽器中,輸入下列網址:

    http://localhost:3000

現在,您可以瀏覽應用程式的網頁、新增書籍和封面圖片、編輯與刪除書籍。

如要離開本機網路伺服器,請按下 Control+C 鍵。

將應用程式部署至 App Engine 彈性環境

  1. 編譯 JavaScript 資產以用於實際工作環境。

    RAILS_ENV=production bundle exec rake assets:precompile
    
  2. 部署範例應用程式。

    gcloud app deploy
    
  3. 在網路瀏覽器中,輸入下列網址。

    https://[YOUR_PROJECT_ID].appspot.com
    

若您更新了應用程式,您可以輸入第一次部署應用程式時使用的指令來部署更新版本。新部署會為您的應用程式建立新版本,並將這個新版本晉升為預設版本。應用程式的較舊版本和相關聯的 VM 執行個體都會保留下來。請注意,這些應用程式版本和 VM 執行個體全部都是計費資源。

您可以刪除應用程式的非預設版本來降低費用。

如何刪除應用程式版本:

  1. 前往 GCP 主控台的「App Engine Versions」(App Engine 版本) 頁面。

    前往版本頁面

  2. 找到您要刪除的非預設應用程式版本,然後點選旁邊的核取方塊。
  3. 按一下頁面頂部的 [刪除] 按鈕, 刪除應用程式版本。

如需有關清除計費資源的完整資訊,請參閱本教學課程最後一個步驟的清除所用資源一節。

應用程式結構

下圖顯示應用程式的元件,以及這些元件彼此之間的連結方式。

二進位資料範例結構

應用程式使用 {storage_name_short}} 來儲存二進位資料 (在這裡是指圖片),同時會繼續針對書籍資訊使用結構化資料庫:Cloud Datastore、Cloud SQL 或 PostgreSQL。

瞭解程式碼

這部分的內容會逐步引導您瞭解應用程式的程式碼,並說明其運作方式。

處理使用者上傳項目

為了讓使用者上傳圖片,新增/編輯表單已修改為允許上傳檔案。這個表單現在分成多個部分。

<%= form_for @book, :html => { :multipart => true } do |f| %>

此外,這個表單有一個用於書籍封面圖片的新欄位。

<div class="form-group">
  <%= f.label :cover_image %>
  <%= f.file_field :cover_image %>
</div>

連線至 Cloud Storage

Bookshelf 應用程式使用 google-cloud-storage Gem 來存取 Google Cloud Platform (GCP) 服務。應用程式會使用您為工作站取得的本機憑證 (在 GCP VM 上執行時則使用環境憑證) 建立連至 Cloud Storage 的連線。

Book 類別的 storage_bucket 類別方法會傳回 settings.yml 檔案中設定所指定的儲存值區參照。這個值區是用來儲存封面圖片的。

require "google/cloud/storage"

class Book < ActiveRecord::Base

  def self.storage_bucket
    @storage_bucket ||= begin
      config = Rails.application.config.x.settings
      storage = Google::Cloud::Storage.new project_id: config["project_id"],
                                           credentials: config["keyfile"]
      storage.bucket config["gcs_bucket"]
    end
  end

上傳至 Cloud Storage

Book 類別有一個新的 upload_image 方法,每當有書籍建立時,系統就會呼叫這個方法。在 upload_image 中,向 image.save 發出的呼叫會使用 cover_image 的內容,在 Cloud Storage 值區中建立新的公開讀取檔案。圖片儲存完畢後,書籍的 image_url 會更新為已儲存圖片的公開網址。

after_create :upload_image, if: :cover_image

def upload_image
  file = Book.storage_bucket.create_file \
    cover_image.tempfile,
    "cover_images/#{id}/#{cover_image.original_filename}",
    content_type: cover_image.content_type,
    acl: "public"

  update_columns image_url: file.public_url
end

從 Cloud Storage 提供圖片

直接從 Cloud Storage 提供圖片很有幫助,因為要求會利用 Google 的全球服務基礎架構,而且應用程式不必回應請求圖片的要求,讓系統釋放更多的 CPU 週期來處理其他的要求。

如要在應用程式中查看封面圖片,請先更新書籍和索引的視圖。

<div class="media">
  <div class="media-left">
    <img src="<%= @book.image_url %>">
  </div>
  <div class="media-body">
    <h4><%= @book.title %> | &nbsp; <small><%= @book.published_on %></small></h4>
    <h5>By <%= @book.author || "unknown" %></h5>
    <p><%= @book.description %></p>
  </div>
</div>

刪除圖片

當您刪除書籍時,書籍模型類別會檢查書籍在 Cloud Storage 值區中是否存有封面圖片。如果有封面圖片,該圖片將遭到刪除。

before_destroy :delete_image, if: :image_url

def delete_image
  image_uri = URI.parse image_url

  if image_uri.host == "#{Book.storage_bucket.name}.storage.googleapis.com"
    # Remove leading forward slash from image path
    # The result will be the image key, eg. "cover_images/:id/:filename"
    image_path = image_uri.path.sub("/", "")

    file = Book.storage_bucket.file image_path
    file.delete
  end
end

更新圖片

更新書籍時,您可以提供新的封面圖片。如果已有封面圖片,現有的圖片會遭到刪除。新圖片會儲存在 Cloud Storage 值區中。

before_update :update_image, if: :cover_image

def update_image
  delete_image if image_url?
  upload_image
end
本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁