A continuación vamos a añadir un segundo modelo a la aplicación. Este nuevo modelo se encargará de gestionar los comentarios de los artículos.
Generando el modelo
Para generar el nuevo modelo usaremos el mismo generador que se explicó anteriormente para el modelo Article
. Esta vez se creará un modelo llamado Comment
que gestionará los comentarios de los artículos. Para crearlo, ejecuta el siguiente comando:
$ bin/rails generate model Comment commenter:string body:text article:references
Como resultado de este comando se generarán cuatro archivos:
File | Purpose |
---|---|
db/migrate/20140120201010_create_comments.rb |
Archivo de migración para crear la tabla comments en la base de datos (en tu caso el nombre del archivo será ligeramente diferente) |
app/models/comment.rb |
El modelo Comment |
test/models/comment_test.rb |
Los tests del modelo |
test/fixtures/comments.yml |
Comentarios de prueba para los tests |
Primero echa un vistazo al archivo app/models/comment.rb
:
class Comment < ActiveRecord::Base belongs_to :article end
Su contenido es muy similar al del modelo Article
generado anteriormente. La única diferencia es la línea belongs_to :article
, que configura una relación para Active Record. En la próxima sencción se explican estas relaciones entre modelos.
Además del modelo, Rails genera un archivo de migración para crear la tabla correspondiente en la base de datos:
class CreateComments < ActiveRecord::Migration def change create_table :comments do |t| t.string :commenter t.text :body # this line adds an integer column called `article_id`. t.references :article, index: true t.timestamps end end end
La línea t.references
crea una columna de tipo clave foránea para establecer la relación entre los dos modelos. Además se crea un índice para esta columna. Como ya tenemos todo preparado, ejecuta el siguiente comando:
$ bin/rake db:migrate
Rails es lo bastante inteligente como para ejecutar solamente las migraciones que todavía no se han ejecutado en la base de datos que se está utilizando. Así que el resultado de ejecutar el comando será:
== CreateComments: migrating ================================================= -- create_table(:comments) -> 0.0115s == CreateComments: migrated (0.0119s) ========================================
Asociando modelos
Las asociaciones de Active Record permiten declarar las relaciones que existen entre dos modelos. En el caso de los comentarios y los artículos, las relaciones se podrían escribir de esta manera:
- Cada comentario pertenece (en inglés, «belongs to») a un artículo.
- Un artículo puede tener muchos (en inglés, «have many») comentarios.
Si te fijas un poco, la sintaxis que utiliza Rails es prácticamente la misma que como se describen las relaciones en inglés. Recuerda la línea del modelo Comment
(archivo app/models/comment.rb
) que establece la relación con Article
:
class Comment < ActiveRecord::Base belongs_to :article end
Ahora edita el archivo app/models/article.rb
para definir el otro extremo de la relación:
class Article < ActiveRecord::Base has_many :comments validates :title, presence: true, length: { minimum: 5 } end
Gracias a estas dos declaraciones (belongs_to
y has_many
), Rails puede hacer casi todo el trabajo automáticamente. Si por ejemplo tienes una variable de instancia llamada @article
que contiene un artículo, puedes obtener todos sus comentarios mediante la isntrucción @article.comments
.
NOTA Consulta el artículo Active Record Associations para obtener más información sobre las asociaciones.
Añadiendo una ruta para los comentarios
En primer lugar debemos añadir una nueva ruta para que Rails sepa dónde queremos navegar para ver los comentarios. Para ello, abre el archivo config/routes.rb
y haz que tenga el siguiente contenido:
resources :articles do resources :comments end
Esta configuración crea la ruta comments
dentro de la ruta articles
que definimos anteriormente. Esta es otra forma de establecer la relación entre los dos modelos.
NOTA Para obtener más información sobre el enrutamiento, consulta la guía Routing Guide.
Generando un controlador
El modelo ya está creado así que ahora podemos dedicarnos a su controlador asociado. De nuevo utilizaremos el comando que genera controladores:
$ bin/rails generate controller Comments
Como resultado de este comando se generan seis archivos y un directorio vacío:
Archivo/Directorio | Propósito |
---|---|
app/controllers/comments_controller.rb |
El controlador Comments |
app/views/comments/ |
Direcotrio donde guardar las vistas del controlador |
test/controllers/comments_controller_test.rb |
El test funcional del controlador |
app/helpers/comments_helper.rb |
El helper para las vistas relacionadas con los comentarios |
test/helpers/comments_helper_test.rb |
Test unitario para el helper |
app/assets/javascripts/comment.js.coffee |
Archivo CoffeeScript para las vistas del controlador |
app/assets/stylesheets/comment.css.scss |
Hoja de estilos CSS para las vistas del controlador |
Como sucede en cualquier blog de Internet, los usuarios podrán añadir comentarios en los artículos y después de hacerlo, se les redirigirá a la página de ese mismo artículo para que puedan ver su comentario publicado. Por eso el controlador CommentsController
deberá incluir un método para crear comentarios y para borrar todos los comentarios de spam que lleguen.
Así que en primer lugar vamos a modificar la plantilla que muestra los artículos (archivoapp/views/articles/show.html.erb
) para que deje crear nuevos comentarios:
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %> | <%= link_to 'Edit', edit_article_path(@article) %>
Este código añade un formulario en la página show
de los artículos para poder crear nuevos comentarios llamando a la acción create
del controlador CommentsController
. En este caso el métodoform_for
utiliza un array que crea rutas anidadas de tipo /articles/1/comments
.
El siguiente paso consiste en crear la acción create
en el archivoapp/controllers/comments_controller.rb
:
class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end
Este controlador es un poco más complejo del que creamos para los artículos. Esta es una de las consecuencias de anidar relaciones. Cada petición relacionada con un comentario debe contener una referencia al artículo con el que está relacionado. Por eso tenemos que buscar primero el modeloArticle
que está relacionado con el comentario.
Además, la acción utiliza algunos de los métodos disponibles para las relaciones. Así por ejemplo se utiliza el método create
sobre @article.comments
para crear y guardar un comentario. Esto hace que el comentario esté automáticamente relacionado con este artículo específico.
Después de crear el nuevo comentario, se redirige al usuario de nuevo a la página que meustra el artículo original mediante el helper article_path(@article)
. Como acabamos de ver, este helperllama a la acción show
del controlador ArticlesController
, que a su vez renderiza la plantillashow.html.erb
. Como esta es la plantilla en la que se debe mostrar el nuevo comentario, añade lo siguiente en el archivo app/views/articles/show.html.erb
:
<p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <% @article.comments.each do |comment| %> <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <% end %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit Article', edit_article_path(@article) %> | <%= link_to 'Back to Articles', articles_path %>
Ahora ya puedes añadir artículos y comentarios en el blog y cada contenido se muestra en el lugar adecuado.
Figura 6.1 Artículo con comentarios