Cómo usar Cloud Storage con Ruby

Esta parte del instructivo de Bookshelf muestra cómo la app de ejemplo almacena imágenes en Google Cloud Storage.

Esta página forma parte de un instructivo de varias páginas. Para comenzar desde el principio y leer las instrucciones de configuración, ve a la app de Bookshelf para Ruby.

Cómo crear un depósito de Cloud Storage

Cloud Storage te permite almacenar y publicar datos binarios. Un depósito es un contenedor de alto nivel para objetos binarios.

Las instrucciones siguientes muestran cómo crear un depósito de Cloud Storage. Los depósitos son los contenedores básicos que conservan tus datos en Cloud Storage.

  1. Ingresa el siguiente comando en una ventana de la terminal:

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

    Donde:

    • [YOUR-BUCKET-NAME] es el nombre de tu depósito de Cloud Storage.
  2. Para ver las imágenes que se subieron en la app de Bookshelf, configura la lista de control de acceso (LCA) predeterminada del depósito como public-read.

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

    Cómo instalar dependencias

    Ve al directorio getting-started-ruby/3-cloud-storage y, luego, ingresa este comando:

    bundle install
    

    Configuraciones

    1. Copia el archivo settings de ejemplo:

      cp config/settings.example.yml config/settings.yml
      
    2. Abre settings.yml para editarlo. Reemplaza los marcadores de posición por los nombres del proyecto y del depósito de almacenamiento.

      Por ejemplo, supongamos que el nombre del proyecto es my-project y el del depósito es my-bucket. Entonces, la sección default del archivo settings.yml se vería así:

      default: &default
        project_id: my-project
        gcs_bucket: my-bucket
      
    3. Copia el archivo database de ejemplo:

      cp config/database.example.yml config/database.yml
      
    4. Configura la app de muestra para que use la misma base de datos que configuraste durante la sección Cómo usar datos estructurados de este instructivo:

      Cloud SQL

      Edita el archivo database.yml. Quita los comentarios de las líneas en la sección de Cloud SQL del archivo. Reemplaza los [PLACEHOLDERS] por los valores específicos de tu instancia y tu base de datos de 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]
      
      • Reemplaza [MYSQL_USER] y [MYSQL_PASS] por el nombre de usuario y la contraseña de la instancia de Cloud SQL que creaste anteriormente.

      • Reemplaza [MYSQL_DATABASE] por el nombre de la base de datos que creaste anteriormente.

      • Reemplaza [YOUR_INSTANCE_CONNECTION_NAME] por Instance Connection Name, correspondiente a tu instancia de Cloud SQL.

      Ejecuta las migraciones:

      bundle exec rake db:migrate
      

      PostgreSQL

      Edita el archivo database.yml. Quita los comentarios a las líneas en la sección de PostgreSQL del archivo. Reemplaza los marcadores de posición your-postgresql-* por los valores específicos de tu instancia y base de datos de PostgreSQL. Por ejemplo, supongamos que la dirección IPv4 es 173.194.230.44, el nombre de usuario es postgres y la contraseña es pword123. Además, supongamos que el nombre de la base de datos es bookshelf. Entonces, la sección de PostgreSQL de tu archivo database.yml se vería así:

      # PostgreSQL Sample Database Configuration
      # ----------------------------------------
        adapter: postgresql
        encoding: unicode
        pool: 5
        username: postgres
        password: pword123
        host: 173.194.230.44
        database: bookshelf
      

      Crea las bases de datos y tablas obligatorias:

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

      Cloud Datastore

      Edita el archivo database.yml. Quita los comentarios de la única línea en la sección de Cloud Datastore del archivo. Reemplaza your-project-id por el ID del proyecto. Por ejemplo, supongamos que el ID del proyecto es my-project; la parte de Cloud Datastore del archivo database.yml se vería así:

      # Google Cloud Datastore Sample Database Configuration
      # ----------------------------------------------------
      dataset_id: my-project
      

      Ejecuta una tarea de rake para copiar los archivos de proyecto de muestra de Cloud Datastore:

      bundle exec rake backend:datastore
      

    Ejecución de la app en la máquina local

    1. Inicia un servidor web local:

      bundle exec rails server
      
    2. En el navegador web, ingresa la siguiente dirección:

      http://localhost:3000

    Ahora puedes navegar por las páginas web de la app y agregar libros con imágenes de portada, así como editar y borrar libros.

    Presiona Control + C para salir del servidor web local.

    Implementación de la app en el entorno flexible de App Engine

    1. Compila recursos de JavaScript para producción:

      RAILS_ENV=production bundle exec rake assets:precompile
      
    2. Implementa la app de muestra:

      gcloud app deploy
      
    3. En el navegador web, ingresa la siguiente dirección. Reemplaza [YOUR_PROJECT_ID] por el ID del proyecto:

      https://[YOUR_PROJECT_ID].appspot.com
      

    Si actualizas tu app, podrás implementar la versión actualizada mediante el mismo comando que usaste para implementar la app por primera vez. La implementación nueva crea una versión nueva de tu app y la convierte a la versión predeterminada. Las versiones anteriores de la app se conservan, al igual que sus instancias de VM asociadas. Ten en cuenta que todas estas instancias de VM y versiones de la app son recursos facturables.

    Para reducir costos, borra las versiones no predeterminadas de la app.

    Para borrar una versión de una app, haz lo siguiente:

    1. En GCP Console, dirígete a la página Versiones de App Engine.

      Ir a la página de Versiones

    2. Haz clic en la casilla de verificación junto a la versión de app no predeterminada que deseas borrar.
    3. Haz clic en el botón Borrar en la parte superior de la página para borrar la versión de la app.

    Para obtener toda la información acerca de la limpieza de los recursos facturables, consulta la sección Limpieza en el paso final de este instructivo.

    Estructura de la aplicación

    El siguiente diagrama muestra los componentes de la aplicación y la manera en que se conectan entre sí.

    Estructura de muestra de datos binarios

    La aplicación usa Cloud Storage para almacenar datos binarios (en este caso, imágenes), mientras continúa usando una base de datos estructurada para la información de los libros, ya sea Cloud Datastore, Cloud SQL o PostgreSQL.

    Comprensión del código

    En esta sección se explica el código de la aplicación y su funcionamiento.

    Cómo controlar las cargas de los usuarios

    A fin de permitir que los usuarios suban imágenes, el formulario para agregar y editar se modificó y ahora permite subir archivos. Ahora, el formulario tiene varias partes:

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

    Además, el formulario tiene un campo nuevo para una imagen de portada del libro:

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

    Cómo conectarse a Cloud Storage

    La app de Bookshelf usa la gema google-cloud-storage para acceder a los servicios de Google Cloud Platform. Esta gema crea una conexión en el servicio de Cloud Storage con las credenciales locales que adquiriste para la estación de trabajo, o credenciales ambientales cuando se ejecuta en VM de Google Cloud Platform.

    El método storage_bucket de la clase Book muestra una referencia al depósito de almacenamiento que se especifica en la configuración de settings.yml. Este depósito se usa para almacenar imágenes de portada.

    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

    Cómo subir archivos a Cloud Storage

    La clase Book tiene un método upload_image nuevo que se llama cada vez que se crea un libro. En upload_image, la llamada a image.save crea un archivo nuevo de lectura pública en el depósito de Cloud Storage mediante el uso del contenido de cover_image. Después de guardar la imagen, la image_url del libro se actualiza a la URL pública de la imagen guardada.

    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

    Cómo publicar imágenes desde Cloud Storage

    Dado que tenemos la URL pública de la imagen, publicarla es simple. Publicarla directamente desde Cloud Storage es útil, ya que las solicitudes aprovechan la infraestructura de publicación global de Google y no es necesario que la aplicación responda a las solicitudes de imágenes, lo que libera ciclos de CPU para otras solicitudes.

    Para que una imagen de portada sea visible en la app, actualizamos la vista del libro y la del índice.

    <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>

    Cómo borrar imágenes

    Cuando borras un libro, el modelo del libro verifica si tiene una imagen de portada guardada en el depósito de Cloud Storage. Si existe una imagen de portada, se borra:

    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

    Cómo actualizar imágenes

    Cuando actualizas un libro, puedes proporcionar una imagen de portada nueva. Si existe una imagen de portada, se borra. La imagen nueva se guarda en el depósito de Cloud Storage:

    before_update :update_image, if: :cover_image
    
    def update_image
      delete_image if image_url?
      upload_image
    end
¿Te sirvió esta página? Envíanos tu opinión: