IIC2143-2020-2 / syllabus

Syllabus de IIC2143 Ingeniería de Software 2020-2
35 stars 10 forks source link

Añadir asociaciones, comando add_column #186

Closed RonaldoSosa closed 4 years ago

RonaldoSosa commented 4 years ago

Hola!Tengo una duda lo que pasa es que para la entrega anterior al momento de agregar las asociaciones a lo modelos no agregamos las referencias como se indico en la ayudantía sino que solo agregamos una variable del tipo string y trabajamos con eso , ahora para hacerlo correctamente estaba intentando remover esa columna y reemplazarla por otra en la cual se haga referencia a otro modelo , me guíe por esta página https://stackoverflow.com/questions/44948748/how-to-change-already-added-string-column-to-a-reference-in-rails , sin embargo aquí me indican que el comando para añadir la columna con referencias es el siguiente : add_column :table, :your_column_name, :integer, references: :your_parent_model Sin embargo , no entiendo la razón de agregar un :integer en este ejemplo o si es necesario agregarlo siempre.

daleal commented 4 years ago

Hola! Lo que sucede es que en realidad, your_column_name en teoría debería ser el id del otro modelo! Te mostraré un ejemplo.

class Author < ApplicationRecord
  has_many :books
end

class Book < ApplicationRecord
  belongs_to :author
end

Puedes ver en este caso que tus instancias de Author deberían tener un atributo books que corresponde a un arreglo de instancias de Book. Por lo mismo, en la base de datos, la tabla para las instancias de Book tendrá una columna que será author_id, y corresponde al id del usuario al que ese libro pertenece. Rails utiliza esta columna detrás de escena para hacer su magia y dejarte llamar author.books directamente desde el código para ahorrarte tener que hacer las consultas tú mismo. En el fondo, las siguientes son equivalentes:

my_author = Author.find(params[:id])

# Rails haciendo magia
my_books = my_author.books

# Haciendo todo a mano
my_books = Book.where(author_id: my_author.id)

Por lo mismo, en el ejemplo que das, your_column_name debería tener un nombre en particular, que corresponde al nombre del modelo relacionado en snake_case seguido de _id. Y dado que es un id, tiene que ser un integer. Hay una forma más simple aún de agregar una referencia a una migración. Rails tiene un "alias" para la línea que escribiste, y se puede agregar una referencia en la migración con lo siguiente:

t.belongs_to :author

De esa forma, la migración entiende que los libros deben contener una referencia al id del autor, y generan la columna automágicamente

RonaldoSosa commented 4 years ago

Entendido!Pero respecto a lo segundo que dijiste de editar la migración , ¿esto no es mala práctica?, recuerdo que en la ayudantía recomendaban usar comandos en lugar de editarlo a mano por así decirlo, partiendo de esto no sería equivalente a usar el comando: rails generate migration AddServiciosToCarretes services:references por ejemplo

daleal commented 4 years ago

Si y no. Déjame explicarte cómo funcionan las migraciones. Dado que tu aplicación está funcionando en un entorno de producción y en tu entorno de desarrollo, Rails debe tener una forma de saber qué cambios estructurales están hechos (a nivel de base de datos) en cada entorno y qué cambios no, para ejecutarlos. Por ejemplo, si tuvieras las migraciones A y B en producción y luego en una nueva branch generas la migración C, cuando subas eso a producción, Rails sabrá que debe ejecutar solamente la migración C y no A ni B (de eso se encarga Rails, tú no debes preocuparte, pero lo importante es que comprendas que solamente ejecuta las migraciones que no se han ejecutado antes). Por lo mismo, si en tu branch en vez de crear la migración C editas la migración B, al subir eso a producción Rails no alterará la base de datos, ya que recuerda que ya ha ejecutado A y B previamente (a pesar de que tú alteraste B antes de volver a subir el código a producción). Eso significa que nunca debes tocar migraciones que ya hayas subido a GitHub (porque quizás otro compañero hizo pull del código que subiste y migró su base de datos con la migración C, pero luego la cambiaste y ahora la base de datos de tu compañero estará "corrupta"). Este último caso no es tan terrible (porque puedes decirle a tu compañero que borre su base de datos y vuelva a ejecutar todas las migraciones, y ahí si se ejecutará la migración editada), pero se puede volver costumbre editar las migraciones ya existentes, y en el entorno de producción no se puede botar la base de datos y re-migrarla (por razones obvias). Por lo mismo, es una muy mala práctica editar migraciones ya existentes, y para tratar incluso de mantenerte alejado de los archivos de migraciones, Rails tiene sus comandos de línea para generar las migraciones por tí (no mucha gente entiende cómo funcionan las migraciones, y el resultado de editarlas a mano cuando no entiendes qué está sucediendo termina inevitablemente en una catástrofe). Sin embargo, si puedes editar a mano de manera segura tus archivos de migraciones, siempre y cuando te preocupes de las siguientes cosas:

  1. Solamente edita archivos de migraciones que no hayan sido commiteados. Así te ahorras los problemas con otra gente de tu equipo migrando sus bases de datos a una versión no final de la migración.
  2. Si creaste una migración, migraste tu base de datos local y ahora decidiste cambiarla porque prefieres, por ejemplo, ponerle otro nombre a la columna (todo esto antes de hacer commit), debes hacer rollback de la migración antes de editarla. Sirve tanto hacer rollback como borrar tu base de datos, pero lo importante es que la migración no esté ejecutada en la base de datos. Una vez hecho el rollback (o una vez eliminada tu base de datos local), puedes alterar el archivo de migración a mano, y luego volver a migrar tu base de datos. Finalmente, cuando tu archivo de migración sea lo que tú quieres que sea, puedes hacer commit para subirlo a GitHub.

Dicho esto, utilizar comandos es siempre seguro, ya que siempre crea una migración nueva, y eso no puede romper el esquema de la base de datos de otras máquinas. Por lo mismo, la decisión queda en tí, y depende de si prefieres tener control granular de qué está sucediendo (crear un archivo de migración "vacío" y editarlo a mano) o de si prefieres que ni siquiera exista la posibilidad de romper tu esquema de base de datos (utilizar comandos para crear la migración completa).

RonaldoSosa commented 4 years ago

Yaaa!!!!Entonces si hago para hacer lo que tu me indicaste de t.belongs_to :author primero deberia hacer db:rollback hasta antes de la migración de los modelos y colocar esto , en cambio si uso lo de rails generate migration AddServiciosToCarretes services:references no seria necesario hacer todo esto aemás de que luego de hacer esto ya podría trabajar directamente con los archivos rb en la carpeta app/models como se nos indico en la ayudantía?

daleal commented 4 years ago

Depende! La migración de los modelos ya está en GitHub? Si está en GitHub, entonces no, deberías agregar una nueva migración en la que agregues el t.belongs_to :author. Si la migración de modelos la hiciste en tu branch y aún no haces commit, entonces si, haces rollback hasta antes de esa migración, la editas y vuelves a migrar. Y si usas el comando, no sería necesario tocar el archivo de la migración. Ojo que en cualquiera de los dos casos deberás indicar la relación en tus modelos (los archivos dentro de app/models), independiente de si editas la migración a mano o usando el comando.

RonaldoSosa commented 4 years ago

Yaaaa!!Graciass!!!En mi caso ya había subido las migraciones a github así que use el comando , y solo para tenerlo claro luego de hacer el rails generate migration AddServiciosToCarretes services:references debo editar los modelos de app/models y recién una vez hecho eso aplicar el rails db:migrate o poría igual editarlos luego del db:migrate y se consideraria las relaciones que aplique?Pregunto esto porque no se si tiene el mismo efecto que cuando recién creo el modelo y lo aplico antes del db migrate , aunque en caso de ya haber hecho el db:migrate ya que aún no hago commit ni nada de eso lo podría solucionar con un db:roolback

daleal commented 4 years ago

Los modelos puedes editarlos cuando prefieras, ya que esas relaciones a Rails solamente le importan cuando corres tu código.

RonaldoSosa commented 4 years ago

Ya me quedo claro ahora !!Gracias!!!!