Cómo usar PostgreSQL con Ruby

Esta parte del instructivo de Bookshelf muestra cómo la app de ejemplo almacena los datos persistentes en una base de datos de PostgreSQL.

Esta muestra usa un servidor de PostgreSQL, que se ejecuta en una instancia de máquina virtual de Google Compute Engine, para almacenar los datos persistentes. Si prefieres usar un servidor de PostgreSQL diferente, puedes implementar esta app de muestra a Cloud Platform y configurarla para usar cualquier servidor de PostgreSQL que elijas.

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 ejecutar PostgreSQL en Compute Engine

  1. Usa la imagen de PostgreSQL proporcionada por Bitnami en Google Cloud Platform Marketplace. Haz clic en Iniciar en Compute Engine. Tardará unos pocos minutos en crear la instancia y en implementar PostgreSQL.

  2. Cuando la implementación se complete, toma nota de los valores de Usuario admin y Contraseña admin para la base de datos de PostgreSQL.

  3. Haz clic en el vínculo de instancia para navegar a los detalles de instancia de VM. Anota la dirección de External IP (IP externo) de tu instancia.

    Captura de pantalla de la instancia de VM

  4. Haz clic en el botón Editar para editar la instancia, y agrega postgres-bitnami al campo Etiquetas de red. Haz clic en Guardar para guardar los cambios.

  5. Crea una regla de firewall que permita el tráfico a PostgreSQL en instancias con la etiqueta de red postgres-bitnami:

    gcloud compute firewall-rules create default-allow-postgresql \
        --allow tcp:5432 \
        --source-ranges 0.0.0.0/0 \
        --target-tags postgres-bitnami \
        --description "Allow access to PostgreSQL from all IPs"
    

Configuraciones

  1. Ve al directorio getting-started-ruby/2-postgresql y copia el archivo database.yml de muestra:

    cp config/database.example.yml config/database.yml
    
  2. Para configurar la base de datos, edita config/database.yml. Configura el valor de database como bookshelf. Reemplaza los marcadores de posición [YOUR_POSTGRES_* por los valores específicos de la instancia y la 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 secret123. Entonces, la sección postgresql_settings del archivo database.yml se vería así:

    postgresql_settings: &postgresql_settings
      adapter: postgresql
      encoding: unicode
      pool: 5
      username: postgres
      password: secret123
      host: 173.194.230.44
      database: bookshelf
    

Cómo instalar dependencias

En el directorio 2-postgresql, ingresa este comando:

bundle install

Cómo crear una base de datos y tablas

  1. Ingresa los siguientes comandos para crear la base de datos y ejecutar migraciones para crear las tablas requeridas:

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

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

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

Estructura de muestra de Auth

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: