Introducción
Ruby on Rails es un marco de aplicación web escrito en Ruby que ofrece a los desarrolladores un enfoque con opiniones sobre el desarrollo de aplicaciones. Trabajar con Rails proporciona a los desarrolladores:
- Convenciones para manejar cosas como el enrutamiento, datos con estado y gestión de activos.
- A firm grounding in the model-view-controller (MCV) architectural pattern, which separates an application’s logic, located in models, from the presentation and routing of application information.
A medida que agregas complejidad a tus aplicaciones de Rails, es probable que trabajes con varios modelos, que representan la lógica empresarial de tu aplicación e interactúan con tu base de datos. Agregar modelos relacionados implica establecer relaciones significativas entre ellos, lo que luego afecta cómo se transmite la información a través de los controladores de tu aplicación y cómo se captura y presenta de vuelta a los usuarios a través de las vistas.
En este tutorial, trabajarás en una aplicación de Rails existente que ofrece a los usuarios datos sobre tiburones. Esta aplicación ya tiene un modelo para manejar datos de tiburones, pero agregarás un recurso anidado para publicaciones sobre tiburones individuales. Esto permitirá a los usuarios desarrollar un amplio conjunto de pensamientos y opiniones sobre tiburones individuales.
Prerrequisitos
Para seguir este tutorial, necesitarás:
- A local machine or development server running Ubuntu 18.04. Your development machine should have a non-root user with administrative privileges and a firewall configured with
ufw
. For instructions on how to set this up, see our Initial Server Setup with Ubuntu 18.04 tutorial. - Node.js y npm instalados en tu máquina local o servidor de desarrollo. Este tutorial utiliza la versión de Node.js 10.16.3 y la versión de npm 6.9.0. Para obtener orientación sobre cómo instalar Node.js y npm en Ubuntu 18.04, sigue las instrucciones en la sección “Instalación utilizando un PPA” de Cómo instalar Node.js en Ubuntu 18.04.
- Ruby, rbenv y Rails instalados en tu máquina local o servidor de desarrollo, siguiendo los Pasos 1-4 en Cómo instalar Ruby on Rails con rbenv en Ubuntu 18.04. Este tutorial utiliza Ruby 2.5.1, rbenv 1.1.2, y Rails 5.2.3.
- SQLite instalado y una aplicación básica de información sobre tiburones creada, siguiendo las instrucciones en Cómo construir una aplicación Ruby on Rails.
Paso 1 — Creación de la estructura básica del modelo anidado
Nuestra aplicación aprovechará las asociaciones de Active Record para establecer una relación entre los modelos Shark
y Post
: las publicaciones pertenecerán a tiburones particulares, y cada tiburón puede tener múltiples publicaciones. Por lo tanto, nuestros modelos Shark
y Post
estarán relacionados a través de las asociaciones belongs_to
y has_many
.
El primer paso para construir la aplicación de esta manera será crear un modelo Post
y los recursos relacionados. Para hacer esto, podemos usar el comando rails generate scaffold
, el cual nos dará un modelo, una migración de base de datos para alterar el esquema de la base de datos, un controlador, un conjunto completo de vistas para gestionar operaciones estándar de Crear, Leer, Actualizar y Borrar (CRUD), y plantillas para parciales, ayudantes y pruebas. Necesitaremos modificar estos recursos, pero usar el comando scaffold
nos ahorrará algo de tiempo y energía ya que genera una estructura que podemos utilizar como punto de partida.
Primero, asegúrate de que estás en el directorio sharkapp
del proyecto Rails que creaste en los requisitos previos:Post
con el siguiente comando:
Crea tus recursos Post
con el siguiente comando:
rails generate scaffold Post body:text shark:references
Con body:text
, estamos indicando a Rails que incluya un campo body
en la tabla posts
de la base de datos, que se relaciona con el modelo Post
. También estamos incluyendo la palabra clave :references
, que establece una asociación entre los modelos Shark
y Post
. Específicamente, esto garantizará que una clave foránea que representa cada entrada de tiburón en la base de datos sharks
se agregue a la base de datos posts
.
Una vez que hayas ejecutado el comando, verás la salida confirmando los recursos que Rails ha generado para la aplicación. Antes de seguir adelante, puedes revisar el archivo de migración de tu base de datos para ver la relación que ahora existe entre tus modelos y tablas de base de datos. Utiliza el siguiente comando para ver el contenido del archivo, asegurándote de sustituir el timestamp de tu propio archivo de migración por lo que se muestra aquí:
Verás la siguiente salida:
Outputclass CreatePosts < ActiveRecord::Migration[5.2]
def change
create_table :posts do |t|
t.text :body
t.references :shark, foreign_key: true
t.timestamps
end
end
end
Como puedes ver, la tabla incluye una columna para una clave foránea de tiburón. Esta clave tendrá la forma de model_name_id
— en nuestro caso, shark_id
.
Rails también ha establecido la relación entre los modelos en otro lugar. Echa un vistazo al modelo Post
recién generado con el siguiente comando:
cat app/models/post.rb
Outputclass Post < ApplicationRecord
belongs_to :shark
end
La asociación belongs_to
establece una relación entre modelos en la que una única instancia del modelo declarado pertenece a una única instancia del modelo nombrado. En el caso de nuestra aplicación, esto significa que una sola publicación pertenece a un solo tiburón.
Además de establecer esta relación, el comando rails generate scaffold
también creó rutas y vistas para las publicaciones, al igual que lo hizo para nuestros recursos de tiburón en Paso 3 de Cómo crear una aplicación Ruby on Rails.
Este es un comienzo útil, pero necesitaremos configurar algunas rutas adicionales y consolidar la asociación de Active Record para el modelo Shark
para que la relación entre nuestros modelos y rutas funcione como se desea.
Paso 2 — Especificar rutas anidadas y asociaciones para el modelo padre
Para agregar la asociación has_many
al modelo Shark
, abre app/models/shark.rb
usando nano
o tu editor favorito:
Agrega la siguiente línea al archivo para establecer la relación entre tiburones y publicaciones:
Algo que vale la pena considerar aquí es qué sucede con las publicaciones una vez que se elimina un tiburón en particular. Probablemente no queremos que las publicaciones asociadas con un tiburón eliminado persistan en la base de datos. Para asegurarnos de que cualquier publicación asociada con un tiburón dado se elimine cuando se elimine ese tiburón, podemos incluir la opción dependent
con la asociación.
class Shark < ApplicationRecord
has_many :posts
validates :name, presence: true, uniqueness: true
validates :facts, presence: true
end
Agrega el siguiente código al archivo para asegurar que la acción destroy
en un tiburón dado elimine cualquier publicación asociada:
Una vez que hayas terminado de hacer estos cambios, guarda y cierra el archivo. Si estás usando nano
, puedes hacer esto presionando CTRL+X
, Y
, luego ENTER
.
class Shark < ApplicationRecord
has_many :posts , dependent: :destroy
validates :name, presence: true, uniqueness: true
validates :facts, presence: true
end
A continuación, abre tu archivo config/routes.rb
para modificar la relación entre tus rutas de recursos:
Actualmente, el archivo luce así:
# Para obtener detalles sobre el DSL disponible dentro de este archivo, consulta http://guides.rubyonrails.org/routing.html
Rails.application.routes.draw do
resources :posts
resources :sharks
root 'sharks#index'
# Para obtener más información sobre el DSL disponible en este archivo, consulte http://guides.rubyonrails.org/routing.html
end
El código actual establece una relación independiente entre nuestras rutas, cuando lo que nos gustaría expresar es una relación dependiente entre tiburones y sus publicaciones asociadas.
Actualicemos nuestra declaración de ruta para hacer que :sharks
sea el padre de :posts
. Actualice el código en el archivo para que se vea como el siguiente:
Rails.application.routes.draw do
resources :sharks do
resources :posts
end
root 'sharks#index'
# Para obtener más información sobre el DSL disponible en este archivo, consulte http://guides.rubyonrails.org/routing.html
end
Guarde y cierre el archivo cuando termine de editar.
Con estos cambios en su lugar, puede pasar a actualizar su controlador posts
.
Paso 3: Actualizar el controlador de publicaciones
La asociación entre nuestros modelos nos da métodos que podemos usar para crear nuevas instancias de publicaciones asociadas con tiburones específicos. Para usar estos métodos, necesitaremos agregarlos a nuestro controlador de publicaciones.
Abra el archivo del controlador de publicaciones:
Actualmente, el archivo se ve así:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /publicaciones
# GET /publicaciones.json
def index
@posts = Post.all
end
# GET /publicaciones/1
# GET /publicaciones/1.json
def show
end
# GET /publicaciones/new
def new
@post = Post.new
end
# GET /publicaciones/1/edit
def edit
end
# POST /publicaciones
# POST /publicaciones.json
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /publicaciones/1
# PATCH/PUT /publicaciones/1.json
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /publicaciones/1
# DELETE /publicaciones/1.json
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Utilice callbacks para compartir configuración común o restricciones entre acciones.
def set_post
@post = Post.find(params[:id])
end
# Nunca confíe en los parámetros de Internet, solo permita la lista blanca a través de.
def post_params
params.require(:post).permit(:body, :shark_id)
end
end
Al igual que nuestro controlador de tiburones, los métodos de este controlador funcionan con instancias de la clase de Publicación
asociada. Por ejemplo, el método nuevo
crea una nueva instancia de la clase Publicación
, el método índice
obtiene todas las instancias de la clase y el método set_publicación
utiliza find
y params
para seleccionar una publicación en particular por su id
. Sin embargo, si queremos que nuestras instancias de publicación estén asociadas con instancias de tiburones en particular, entonces necesitaremos modificar este código, ya que la clase Publicación
actualmente opera como una entidad independiente.
Nuestras modificaciones harán uso de dos cosas:
- Los métodos que se hicieron disponibles para nosotros cuando añadimos las asociaciones
belongs_to
yhas_many
a nuestros modelos. Específicamente, ahora tenemos acceso al métodobuild
gracias a la asociaciónhas_many
que definimos en nuestro modeloShark
. Este método nos permitirá crear una colección de objetos de publicaciones asociadas con un objeto tiburón particular, utilizando la clave foráneashark_id
que existe en nuestra base de datos deposts
. - Las rutas y ayudantes de enrutamiento que se hicieron disponibles cuando creamos una ruta anidada de
posts
. Para obtener una lista completa de ejemplos de rutas que se vuelven disponibles cuando creas relaciones anidadas entre recursos, consulta la documentación de Rails. Por ahora, será suficiente para nosotros saber que para cada tiburón específico —digamossharks/1
— habrá una ruta asociada para las publicaciones relacionadas con ese tiburón:sharks/1/posts
. También habrá ayudantes de enrutamiento comoshark_posts_path(@shark)
yedit_sharks_posts_path(@shark)
que se refieren a estas rutas anidadas.En el archivo, comenzaremos escribiendo un método, get_shark
, que se ejecutará antes de cada acción en el controlador. Este método creará una variable de instancia local@shark
encontrando una instancia de tiburón porshark_id
. Con esta variable disponible para nosotros en el archivo, será posible relacionar publicaciones con un tiburón específico en los otros métodos.
En el archivo, comenzaremos escribiendo un método, get_shark
, que se ejecutará antes de cada acción en el controlador. Este método creará una instancia local de @shark
buscando una instancia de tiburón por shark_id
. Con esta variable disponible en el archivo, será posible relacionar publicaciones con un tiburón específico en los otros métodos.
Encima de los otros métodos private
en la parte inferior del archivo, agregue el siguiente método:
. . .
private
def get_shark
@shark = Shark.find(params[:shark_id])
end
# Utilizar callbacks para compartir configuración o restricciones comunes entre acciones.
. . .
A continuación, agregue el filtro correspondiente a la parte superior del archivo, antes del filtro existente:
class PostsController < ApplicationController
before_action :get_shark
Esto garantizará que get_shark
se ejecute antes de cada acción definida en el archivo.
A continuación, puede usar esta instancia de @shark
para reescribir el método index
. En lugar de obtener todas las instancias de la clase Post
, queremos que este método devuelva todas las instancias de publicaciones asociadas con una instancia de tiburón específica.
Modifique el método index
para que se vea así:
. . .
def index
@posts = @shark.posts
end
. . .
El método new
necesitará una revisión similar, ya que queremos que una nueva instancia de publicación esté asociada con un tiburón específico. Para lograr esto, podemos usar el método build
, junto con nuestra variable de instancia local @shark
.
Cambie el método new
para que se vea así:
. . .
def new
@post = @shark.posts.build
end
. . .
Este método crea un objeto de publicación que está asociado con la instancia de tiburón específica desde el método get_shark
.
Actualiza el método create
para que se vea así:
A continuación, echa un vistazo al método update
. Este método utiliza una variable de instancia @post
, la cual no está establecida explícitamente en el propio método. ¿De dónde proviene esta variable?
def create
@post = @shark.posts.build(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
Echa un vistazo a los filtros en la parte superior del archivo. El segundo filtro before_action
auto-generado proporciona una respuesta:
El método update
(al igual que show
, edit
, y destroy
) toma una variable @post
del método set_post
. Ese método, listado bajo el método get_shark
con nuestros otros métodos private
, actualmente se ve así:
class PostsController < ApplicationController
before_action :get_shark
before_action :set_post, only: [:show, :edit, :update, :destroy]
. . .
Siguiendo con los métodos que hemos utilizado en otras partes del archivo, necesitaremos modificar este método para que @post
se refiera a una instancia particular en la colección de publicaciones asociadas con un tiburón específico. Ten en cuenta el método build
aquí: gracias a las asociaciones entre nuestros modelos y los métodos (como build
) que están disponibles para nosotros gracias a esas asociaciones, cada una de nuestras instancias de publicaciones es parte de una colección de objetos asociados con un tiburón específico. Por lo tanto, tiene sentido que al consultar una publicación en particular, consultemos la colección de publicaciones asociadas con un tiburón específico.set_post
para que se vea así:Post
por id
, en su lugar buscamos un id
coincidente en la colección de publicaciones asociadas con un tiburón específico.
. . .
private
. . .
def set_post
@post = Post.find(params[:id])
end
. . .
Manteniendo los métodos que hemos utilizado en otros lugares del archivo, necesitamos modificar este método para que @post
se refiera a una instancia específica en la colección de publicaciones asociadas con un tiburón en particular. Ten en cuenta el método build
aquí: gracias a las asociaciones entre nuestros modelos y los métodos (como build
) disponibles para nosotros debido a esas asociaciones, cada instancia de nuestra publicación es parte de una colección de objetos asociados con un tiburón específico. Por lo tanto, tiene sentido que al consultar una publicación en particular, busquemos la colección de publicaciones asociadas con un tiburón específico.
Actualiza set_post
para que se vea así:
. . .
private
. . .
def set_post
@post = @shark.posts.find(params[:id])
end
. . .
En lugar de encontrar una instancia específica de toda la clase Post
por id
, buscamos un id
coincidente en la colección de publicaciones asociadas con un tiburón específico.
Con ese método actualizado, podemos ver los métodos update
y destroy
.
El método update
hace uso de la variable de instancia @post
de set_post
y la usa con los post_params
que el usuario ha ingresado en el formulario edit
. En caso de éxito, queremos que Rails envíe al usuario de vuelta a la vista index
de las publicaciones asociadas con un tiburón específico. En caso de errores, Rails volverá a renderizar la plantilla edit
.
En este caso, el único cambio que necesitaremos hacer es en la declaración redirect_to
, para manejar las actualizaciones exitosas. Actualícelo para redireccionar a shark_post_path(@shark)
, lo que redireccionará a la vista index
de las publicaciones del tiburón seleccionado:
. . .
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
. . .
A continuación, haremos un cambio similar en el método destroy
. Actualice el método redirect_to
para redireccionar las solicitudes a shark_posts_path(@shark)
en caso de éxito:
. . .
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
. . .
Este es el último cambio que haremos. Ahora tiene un archivo de controlador de publicaciones que se ve así:
class PostsController < ApplicationController
before_action :get_shark
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
@posts = @shark.posts
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
@post = @shark.posts.build
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
@post = @shark.posts.build(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def get_shark
@shark = Shark.find(params[:shark_id])
end
# Utilice devoluciones de llamada para compartir configuración o restricciones comunes entre acciones.
def set_post
@post = @shark.posts.find(params[:id])
end
# Nunca confíe en los parámetros de internet aterradora, solo permita la lista blanca.
def post_params
params.require(:post).permit(:body, :shark_id)
end
end
El controlador gestiona cómo se pasa la información de las plantillas de vista a la base de datos y viceversa. Nuestro controlador ahora refleja la relación entre nuestros modelos Shark
y Post
, en la que las publicaciones están asociadas con tiburones particulares. Podemos pasar a modificar las plantillas de vista en sí, que son donde los usuarios pasarán y modificarán la información de las publicaciones sobre tiburones particulares.
Paso 4 — Modificando Vistas
Nuestras revisiones de la plantilla de vista implicarán cambiar las plantillas que se relacionan con las publicaciones y también modificar nuestra vista show
de tiburones, ya que queremos que los usuarios vean las publicaciones asociadas con tiburones específicos.
Comencemos con la plantilla fundamental para nuestras publicaciones: el parcial form
que se reutiliza en múltiples plantillas de publicaciones. Abre ese formulario ahora:
En lugar de pasar solo el modelo post
al ayudante de formulario form_with
, pasaremos tanto el modelo shark
como el modelo post
, con post
establecido como recurso secundario.
Cambia la primera línea del archivo para que se vea así, reflejando la relación entre nuestros recursos tiburón y publicación:
<%= form_with(model: [@shark, post], local: true) do |form| %>
. . .
A continuación, elimina la sección que enumera el shark_id
del tiburón relacionado, ya que esta no es información esencial en la vista.
El formulario terminado, completo con nuestras ediciones en la primera línea y sin la sección eliminada de shark_id
, se verá así:
<%= form_with(model: [@shark, post], local: true) do |form| %>
<% if post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Guarda y cierra el archivo cuando termines de editar.
A continuación, abre la vista index
, que mostrará las publicaciones asociadas con un tiburón en particular:
A continuación, cambie la redirección de Show
para dirigir a los usuarios a la vista show
del tiburón asociado, ya que es probable que quieran una forma de volver al tiburón original. Podemos hacer uso de la variable de instancia @shark
que establecimos en el controlador aquí, ya que Rails hace que las variables de instancia creadas en el controlador estén disponibles para todas las vistas. También cambiaremos el texto del enlace de Show
a Show Shark
, para que los usuarios comprendan mejor su función.
Actualice esta línea a lo siguiente:
En la siguiente línea, queremos asegurarnos de que los usuarios sean dirigidos al camino anidado correcto cuando vayan a editar una publicación. Esto significa que en lugar de ser dirigidos a posts/post_id/edit
, los usuarios serán dirigidos a sharks/shark_id/posts/post_id/edit
. Para hacer esto, usaremos el ayudante de enrutamiento shark_post_path
y nuestros modelos, que Rails tratará como URLs. También actualizaremos el texto del enlace para que su función sea más clara.
Actualice la línea de Edit
para que se vea así:
. . .
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.body %></td>
<td><%= post.shark.name %></td>
. . .
A continuación, agreguemos un cambio similar al enlace Destroy
, actualizando su función en la cadena y agregando nuestros recursos shark
y post
:
Finalmente, en el fondo del formulario, querremos actualizar el camino de New Post
para llevar a los usuarios al camino anidado apropiado cuando quieran crear una nueva publicación. Actualice la última línea del archivo para hacer uso del ayudante de enrutamiento new_shark_post_path(@shark)
:
. . .
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.body %></td>
<td><%= post.shark.name %></td>
<td><%= link_to 'Show Shark', [@shark] %></td>
Guarda y cierra el archivo cuando hayas terminado de editar.
Las otras ediciones que haremos en las vistas de publicaciones no serán tan numerosas, ya que nuestras otras vistas usan el parcial form
que ya hemos editado. Sin embargo, querremos actualizar las referencias de link_to
en las otras plantillas de publicaciones para reflejar los cambios que hemos realizado en nuestro parcial form
.
. . .
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.body %></td>
<td><%= post.shark.name %></td>
<td><%= link_to 'Show Shark', [@shark] %></td>
<td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
Abre app/views/posts/new.html.erb
:
. . .
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.body %></td>
<td><%= post.shark.name %></td>
<td><%= link_to 'Show Shark', [@shark] %></td>
<td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
<td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
Actualiza la referencia de link_to
en la parte inferior del archivo para hacer uso del ayudante shark_posts_path(@shark)
:
. . .
<%= link_to 'New Post', new_shark_post_path(@shark) %>
Guarda y cierra el archivo cuando hayas terminado de realizar este cambio.
<p id="notice"><%= notice %></p>
<h1>Posts</h1>
<table>
<thead>
<tr>
<th>Body</th>
<th>Shark</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.body %></td>
<td><%= post.shark.name %></td>
<td><%= link_to 'Show Shark', [@shark] %></td>
<td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
<td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Post', new_shark_post_path(@shark) %>
A continuación, abre la plantilla edit
:
Además de la ruta Back
, actualizaremos Show
para reflejar nuestros recursos anidados. Cambia las dos últimas líneas del archivo para que se vean así:
Guarda y cierra el archivo.
A continuación, abre la plantilla show
:Edit
y Back
en la parte inferior del archivo:show
para nuestros tiburones para que las publicaciones sean visibles para tiburones individuales. Abre ese archivo ahora:Posts
al formulario y un enlace Add Post
en la parte inferior del archivo.
. . .
<%= link_to 'Back', shark_posts_path(@shark) %>
Guarda y cierra el archivo cuando hayas terminado de hacer este cambio.
A continuación, abre la plantilla edit
:
Además del camino Back
, actualizaremos Show
para reflejar nuestros recursos anidados. Cambia las dos últimas líneas del archivo para que se vean así:
. . .
<%= link_to 'Show', [@shark, @post] %> |
<%= link_to 'Back', shark_posts_path(@shark) %>
Guarda y cierra el archivo.
A continuación, abre la plantilla show
:
nano app/views/posts/show.html.erb
Realiza los siguientes cambios en los caminos Edit
y Back
al final del archivo:
. . .
<%= link_to 'Edit', edit_shark_post_path(@shark, @post) %> |
<%= link_to 'Back', shark_posts_path(@shark) %>
Guarda y cierra el archivo cuando hayas terminado.
Como paso final, querríamos actualizar la vista show
para nuestras tiburones para que las publicaciones sean visibles para tiburones individuales. Abre ese archivo ahora:
Nuestros cambios aquí incluirán agregar una sección Posts
al formulario y un enlace Add Post
al final del archivo.
Debajo de los Facts
de un tiburón determinado, agregaremos una nueva sección que itere a través de cada instancia en la colección de publicaciones asociadas con este tiburón, mostrando el body
de cada publicación.
Agrega el siguiente código debajo de la sección Facts
del formulario, y por encima de las redirecciones al final del archivo:
. . .
<p>
<strong>Facts:</strong>
<%= @shark.facts %>
</p>
<h2>Posts</h2>
<% for post in @shark.posts %>
<ul>
<li><%= post.body %></li>
</ul>
<% end %>
<%= link_to 'Edit', edit_shark_path(@shark) %> |
. . .
A continuación, agrega una nueva redirección para permitir a los usuarios agregar una nueva publicación para este tiburón en particular:
. . .
<%= link_to 'Edit', edit_shark_path(@shark) %> |
<%= link_to 'Add Post', shark_posts_path(@shark) %> |
<%= link_to 'Back', sharks_path %>
Guarda y cierra el archivo cuando hayas terminado de editar.
Has realizado cambios en los modelos, controladores y vistas de su aplicación para asegurar que las publicaciones siempre estén asociadas con un tiburón en particular. Como último paso, podemos agregar algunas validaciones a nuestro modelo Post
para garantizar la consistencia en los datos que se guardan en la base de datos.
Paso 5: Agregar validaciones y probar la aplicación
En Paso 5 de Cómo crear una aplicación Ruby on Rails, agregaste validaciones a tu modelo Shark
para asegurar uniformidad y consistencia en los datos que se guardan en la base de datos sharks
. Ahora tomaremos un paso similar para garantizar garantías para la base de datos posts
también.
Abre el archivo donde está definido tu modelo Post
:
Aquí, queremos asegurarnos de que las publicaciones no estén en blanco y de que no dupliquen contenido que otros usuarios puedan haber publicado. Para lograr esto, agrega la siguiente línea al archivo:
class Post < ApplicationRecord
belongs_to :shark
validates :body, presence: true, uniqueness: true
end
Guarda y cierra el archivo cuando termines de editar.
Con este último cambio en su lugar, estás listo para ejecutar tus migraciones y probar la aplicación.
Primero, ejecute sus migraciones:
Luego, inicie su servidor. Si está trabajando localmente, puede hacerlo ejecutando:
Si está trabajando en un servidor de desarrollo, ejecute el siguiente comando en su lugar:
Navegue hasta la raíz de su aplicación en http://localhost:3000
o http://su_ip_del_servidor:3000
.
El tutorial previo de proyecto Rails le guió a través de la adición y edición de una entrada de tiburón Blanco Grande. Si no ha agregado ningún tiburón adicional, la página de inicio de la aplicación se verá así:
Haga clic en Mostrar junto al nombre del Blanco Grande. Esto lo llevará a la vista mostrar
para este tiburón. Verá el nombre del tiburón y sus datos, y un encabezado Publicaciones sin contenido. Agreguemos una publicación para poblar esta parte del formulario.
Haga clic en Agregar Publicación debajo del encabezado Publicaciones. Esto lo llevará a la vista índice
de publicaciones, donde tendrá la oportunidad de seleccionar Nueva Publicación:
Gracias a los mecanismos de autenticación que implementó en Paso 6 de Cómo construir una aplicación Ruby on Rails, es posible que se le solicite autenticarse con el nombre de usuario y contraseña que creó en ese Paso, dependiendo de si ha creado una nueva sesión o no.
Haz clic en Nuevo Post, lo que te llevará a tu plantilla de publicación nueva
:
En el campo Cuerpo, escribe, “¡Estos tiburones dan miedo!”
Haz clic en Crear Publicación. Serás redireccionado a la vista índice
de todas las publicaciones que pertenecen a este tiburón:
Con nuestros recursos de publicación funcionando, ahora podemos probar nuestras validaciones de datos para asegurarnos de que solo se guarde la información deseada en la base de datos.
Desde la vista índice
, haz clic en Nuevo Post. En el campo Cuerpo del nuevo formulario, intenta ingresar “¡Estos tiburones dan miedo!” nuevamente:
Haz clic en Crear Publicación. Verás el siguiente error:
Haz clic en Volver para regresar a la página principal de publicaciones.
Para probar nuestra otra validación, haz clic en Nuevo Post nuevamente. Deja la publicación en blanco y haz clic en Crear Publicación. Verás el siguiente error:
Con tus recursos anidados y validaciones funcionando correctamente, ahora tienes una aplicación Rails funcional que puedes usar como punto de partida para un desarrollo adicional.
Conclusión
Con su aplicación Rails en su lugar, ahora puede trabajar en cosas como el estilo y el desarrollo de otros componentes de front-end. Si desea obtener más información sobre enrutamiento y recursos anidados, la documentación de Rails es un excelente lugar para comenzar.
Para obtener más información sobre la integración de frameworks de front-end con su aplicación, eche un vistazo a Cómo configurar un proyecto Ruby on Rails con un front-end de React.