Cómo usar Cloud SQL con Ruby

Esta parte del instructivo de Bookshelf muestra cómo la app de ejemplo almacena los datos persistentes en Google Cloud SQL.

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 una instancia de Cloud SQL

Tras la implementación, la aplicación usa el proxy de Cloud SQL integrado en el entorno de App Engine para comunicarse con la instancia de Cloud SQL. Sin embargo, para probar tu aplicación de manera local, debes instalar y usar una copia local del proxy de Cloud SQL en tu entorno de desarrollo.

Obtén más información acerca del proxy de Cloud SQL.

Para realizar tareas administrativas básicas en la instancia de Cloud SQL, usa el cliente MySQL.

Instala el proxy de SQL

Descarga y también instala el proxy de Cloud SQL. El proxy de Cloud SQL se usa para conectarte a tu instancia de Cloud SQL cuando se ejecuta de manera local.

Linux de 64 bits

  1. Descarga el proxy:
    wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
    
  2. Haz que el proxy sea ejecutable:
    chmod +x cloud_sql_proxy
    

Linux de 32 bits

  1. Descarga el proxy:
    wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
    
  2. Haz que el proxy sea ejecutable:
    chmod +x cloud_sql_proxy
    

macOS de 64 bits

  1. Descarga el proxy:
    curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
    
  2. Haz que el proxy sea ejecutable:
    chmod +x cloud_sql_proxy
    

macOS de 32 bits

  1. Descarga el proxy:
    curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
    
  2. Haz que el proxy sea ejecutable:
    chmod +x cloud_sql_proxy
    

Windows de 64 bits

Para descargar el proxy, haz clic derecho en https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe, selecciona "Guardar vínculo como…" y cámbiale el nombre a cloud_sql_proxy.exe.

Windows de 32 bits

Para descargar el proxy, haz clic derecho en https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe, selecciona "Guardar vínculo como…" y cámbiale el nombre a cloud_sql_proxy.exe.
Si tu sistema operativo no se incluye aquí, también puedes compilar el proxy desde la fuente.

Crear una instancia de Cloud SQL

  1. Crea una instancia de Cloud SQL para MySQL de segunda generación. Asigna a la instancia el nombre [YOUR_INSTANCE_NAME] o uno similar. Es posible que la instancia tarde algunos minutos en estar lista. Cuando esté lista, debería poder verse en la lista de instancias.
  2. Ahora, usa el SDK de Cloud desde la línea de comandos para ejecutar el siguiente comando. Copia el valor que se muestra para connectionName, ya que lo necesitarás en el paso siguiente.
    gcloud sql instances describe [YOUR_INSTANCE_NAME]

    El valor de connectionName tiene el formato [PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME].

Inicializa la instancia de Cloud SQL

  1. Antes de usar ./cloud_sql_proxy por primera vez, debes crear un directorio donde se ubicarán los sockets del proxy:

    sudo mkdir /cloudsql
    sudo chmod 0777 /cloudsql
    
  2. Inicia el proxy de Cloud SQL con el valor de connectionName del paso anterior.

    ./cloud_sql_proxy -instances="[YOUR_INSTANCE_CONNECTION_NAME]" -dir=/cloudsql
    

    Reemplaza [YOUR_INSTANCE_CONNECTION_NAME] por el nombre de conexión de la instancia de Cloud SQL.Este paso establece una conexión entre la computadora local y la instancia de Cloud SQL a fin de realizar pruebas locales. Mantén el proxy de Cloud SQL en ejecución durante todo el tiempo que realices pruebas locales en la aplicación.

  3. Luego, deberás crear un usuario de Cloud SQL nuevo con una base de datos asociada.

    CONSOLE

    1. Crea una base de datos nueva con GCP Console para la instancia [YOUR_INSTANCE_NAME] de Cloud SQL. Por ejemplo, puedes usar el nombre [MYSQL_DATABASE].
    2. Crea un usuario nuevo con GCP Console para la instancia [YOUR_INSTANCE_NAME] de Cloud SQL.

    CLIENTE MYSQL

    1. En una pestaña independiente de la línea de comandos, usa el cliente MySQL o un programa similar para conectarte a la instancia. Ingresa la contraseña raíz que configuraste cuando se te indique.
      mysql --socket "/cloudsql/[YOUR_INSTANCE_CONNECTION_NAME]" --user root --password
      
    2. Usa los siguientes comandos para crear las bases de datos, los usuarios y los permisos de acceso requeridos para tu base de datos de Cloud SQL. Reemplaza [MYSQL_USER] y [MYSQL_PASSWORD] por tu nombre de usuario y contraseña.
      CREATE DATABASE [MYSQL_DATABASE];
      CREATE USER '[MYSQL_USER]' IDENTIFIED BY '[MYSQL_PASSWORD]';
      GRANT ALL ON . TO '[MYSQL_USER]';
      

Configuraciones

  1. Ve al directorio getting-started-ruby/2-cloud-sql y copia el archivo database.example.yml:

     cp config/database.example.yml config/database.yml
    
  2. Para configurar la base de datos, edita config/database.yml.

    mysql_settings: &mysql_settings
      adapter: mysql2
      encoding: utf8
      pool: 5
      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.

  3. Para preparar App Engine con Cloud SQL, edita app.yaml.

    beta_settings:
      # The connection name of your instance on its Overview page in the Google
      # Cloud Platform Console, or use `[YOUR_PROJECT_ID]:[YOUR_REGION]:[YOUR_INSTANCE_NAME]`
      cloud_sql_instances: [YOUR_INSTANCE_CONNECTION_NAME]
    • Reemplaza [YOUR_INSTANCE_CONNECTION_NAME] por Instance Connection Name, correspondiente a tu instancia de Cloud SQL.

Cómo instalar dependencias

En el directorio 2-cloud-sql, ingresa este comando:

bundle install

Cómo crear una base de datos y tablas

  1. Crea la base de datos y ejecuta migraciones para crear la tabla necesaria:

    bundle exec rake db:migrate
    

    Cuando se complete este paso, aparecerá un mensaje que te indicará que la migración de CreateBooks se ejecutó correctamente:

    == 20150706182833 CreateBooks: migrating ===============================
    -- create_table(:books)
    -> 0.4526s
    == 20150706182833 CreateBooks: migrated (0.4528s) ======================
    

    La migración de CreateBooks crea una tabla books nueva con columnas para almacenar el título, el autor, la fecha de publicación y la descripción del libro:

    class CreateBooks < ActiveRecord::Migration
      def change
        create_table :books do |t|
          t.string :title, required: true
          t.string :author
          t.date :published_on
          t.text :description
          t.timestamps null: false
        end
      end
    end
    

Cómo ejecutar 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, 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. In the GCP Console, go to the Versions page for App Engine.

    Go to the Versions page

  2. Select the checkbox for the non-default app version you want to delete.
  3. Click Delete to delete the app version.

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

Este diagrama muestra los componentes de la app y la manera en que se conectan entre sí.

Proceso y estructura de la implementación de la app de Bookshelf

Comprensión del código

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

Cómo mostrar una lista de libros

Cuando visitas la página principal de la app, te diriges a la acción index de la clase BooksController. Esto se configura en config/routes.rb:

Rails.application.routes.draw do

  # Route root of application to BooksController#index action
  root "books#index"

  # Restful routes for BooksController
  resources :books

end

La acción BookController#index recupera una lista de libros desde la base de datos de Cloud SQL. La app muestra como máximo 10 libros en cada página web, por lo que la lista recuperada depende de la página que el usuario esté mirando. Por ejemplo, supongamos que hay 26 libros en la base de datos y el usuario se encuentra en la tercera página (/?page=3). En ese caso, params[:page] equivale a 3, que se asigna a la variable page_number. Luego, se recupera una lista de 6 libros, y se empieza con un desfase de 20, y se asigna a @books.

class BooksController < ApplicationController

  PER_PAGE = 10

  def index
    page_number = params[:page] ? params[:page].to_i : 1
    book_offset = PER_PAGE * (page_number - 1)
    @books      = Book.limit(PER_PAGE).offset(book_offset)
    @next_page  = page_number + 1 if @books.count == PER_PAGE
  end

La clase Book es un modelo de ActiveRecord simple que representa un solo libro en la tabla de libros:

class Book < ActiveRecord::Base
  validates :title, presence: true
end

En routes.rb, la llamada a resources :books configura rutas con la tecnología de REST para crear, leer, actualizar y borrar libros, que se dirigen a las acciones correspondientes en la clase BooksController.

Después de que BooksController.index recupera una lista de libros, el código de Ruby incorporado a books/index.html.erb procesa la lista:

<% @books.each do |book| %>
  <div class="media">
    <%= link_to book_path(book) do %>
      <div class="media-body">
        <h4><%= book.title %></h4>
        <p><%= book.author %></p>
      </div>
    <% end %>
  </div>
<% end %>

<% if @next_page %>
  <nav>
    <ul class="pager">
      <li><%= link_to "More", books_path(page: @next_page) %></li>
    </ul>
  </nav>
<% end %>

Cómo mostrar detalles de los libros

Cuando haces clic en un libro en la página web, la acción BookController#show recupera el libro, a partir de su ID, desde la tabla de libros:

def show
  @book = Book.find params[:id]
end

Luego, el código de Ruby incorporado a show.html.erb muestra los detalles del libro:

<div class="media">
  <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 crear libros

Cuando haces clic en Agregar libro en la página web, la acción BooksController#new crea un libro nuevo. El código Ruby incorporado a new.html.erb apunta a _form.html.erb, que muestra el formulario para agregar un libro nuevo:

<%= form_for @book do |f| %>
  <div class="form-group">
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>
  <div class="form-group">
    <%= f.label :author %>
    <%= f.text_field :author %>
  </div>
  <div class="form-group">
    <%= f.label :published_on, "Date Published" %>
    <%= f.date_field :published_on %>
  </div>
  <div class="form-group">
    <%= f.label :description %>
    <%= f.text_area :description %>
  </div>
  <button class="btn btn-success" type="submit">Save</button>
<% end %>

Cuando envías el formulario, la acción BooksController#create guarda el libro en la base de datos. Si el libro nuevo se guarda correctamente, se muestra la página del libro. De lo contrario, se vuelve a mostrar el formulario junto con mensajes de error. El método book_params usa parámetros estrictos para especificar los campos del formulario que están permitidos. En este caso, solo están permitidos el título, el autor, la fecha de publicación y la descripción del libro:

def create
  @book = Book.new book_params

  if @book.save
    flash[:success] = "Added Book"
    redirect_to book_path(@book)
  else
    render :new
  end
end

private

def book_params
  params.require(:book).permit(:title, :author, :published_on, :description)
end

Cómo editar libros

Cuando haces clic en Editar libro en la página web, la acción BooksController#update recupera el libro de la base de datos. El código Ruby incorporado a edit.html.erb apunta a _form.html.erb, que muestra el formulario para editar el libro:

def update
  @book = Book.find params[:id]

  if @book.update book_params
    flash[:success] = "Updated Book"
    redirect_to book_path(@book)
  else
    render :edit
  end
end

Cuando envías el formulario, la acción BooksController#update guarda el libro en la base de datos. Si el libro nuevo se guarda correctamente, se muestra la página del libro. De lo contrario, se vuelve a mostrar el formulario junto con mensajes de error.

Cómo borrar libros

Cuando haces clic en Borrar libro en la página web, la acción BooksController#destroy borra el libro del almacén de datos y muestra la lista de libros:

def destroy
  @book = Book.find params[:id]
  @book.destroy
  redirect_to books_path
end
¿Te sirvió esta página? Envíanos tu opinión: