Especificar el nombre de la columna en una migración de "referencias"


124

Quiero hacer un migrationen Rails, haciendo referencia a otra tabla. Por lo general, haría algo como:

add_column :post, :user, :references

Esto crea una columna nombrada user_iden la poststabla. Pero, ¿qué pasa si, en lugar de user_id, quiero algo así author_id? ¿Cómo puedo hacer eso?

Respuestas:


59

Hazlo manualmente:

add_column :post, :author_id, :integer

pero ahora, cuando cree la declaración belong_to, tendrá que modificarla, por lo que ahora debe llamar

def post
    belongs_to :user, :foreign_key => 'author_id'
end

1
¿No tengo que agregar ningún índice?
— caarlos0

1
Sí, deberá crear un índice en la migración.
— Tom Harrison

1
Trucos de Rails: en realidad no usa índices por defecto. Ahora, si desea índices (que son una gran idea, a pesar del hecho de que los rieles los ignorarán por completo), puede agregarlos. Querrá consultar la guía que enlace para obtener más información sobre las migraciones en general, e incluso puede terminar poniendo código SQL de llamada directamente en su migración. Diría que lo ignore, ya que no es una parte normal de los rieles, obtendrá 0 rendimiento, ya que las consultas SQL generadas por defecto de los rieles no lo aprovechan. enlace
— mschultz

hmm entendido. ¡Muchas gracias!
— caarlos0

usando schema_plusgema, t.references :category, index: true, foreign_key: true, references: :match_categoriestambién funcionó para mí en el archivo de migración.
— elquimista

251

Para rieles 5+

Definición inicial:

Si está definiendo su Posttabla de modelos, puede establecer references, indexy foreign_keyen una línea:

t.references :author, index: true, foreign_key: { to_table: :users }

Actualización existente:

Si agrega referencias a una tabla existente, puede hacer esto:

add_reference :posts, :author, foreign_key: { to_table: :users }

Nota: El valor predeterminado para indexes verdadero.


¿La definición inicial permitirá nulos? Si no es así, ¿conoce la alternativa anulable?
— Vorpulus Lyphane

55
Esta definición permite nulls. Para no permitirlos, agregue la opción habitual null: false.
— Ashitaka

Gracias. Para la "Definición inicial", creo que el "índice: verdadero" no es necesario. Recibo el mismo cambio de esquema con o sin él. No importa; Acabo de ver tu nota al final.
— Joey

¡Gracias, esto es lo que estaba buscando!
— Philippe B.

250

En Rails 4.2+ también puedes configurar claves foráneas en la base de datos, lo cual es una gran idea .

Para asociaciones simples, esto se puede hacer también al t.referencesagregar foreign_key: true, pero en este caso necesitará dos líneas.

# The migration
add_reference :posts, :author, index: true
add_foreign_key :posts, :users, column: :author_id

# The model
belongs_to :author, class_name: "User"

2
Gracias, pero la pregunta está etiquetada como Rails3, estoy feliz de ayudarlo
— Ecoologic

2
Ooh, no me di cuenta de eso. Bueno, ha sido muy útil para mí. :)
— bonh

2
¡Casi había perdido la esperanza cuando vi esto! Gracias @ecoologic!
— Dan Williams

2
@ecoologic, solo una cosa que quizás desee agregar, add_foreign_key es solo rails 4.2+. ;)
— Dan Williams

44
No estoy seguro de que necesite la references: :usersopción en la add_referencellamada. No lo veo documentado en los documentos y parece funcionar de mi parte sin él.
— jakecraige

87

En los rieles 4, cuando usa postgresql y la gema schema_plus , puede escribir

add_reference :posts, :author, references: :users

Esto creará una columna author_id, que se refiere correctamente users(id).

Y en tu modelo, escribes

belongs_to :author, class_name: "User"

Tenga en cuenta que al crear una nueva tabla puede escribirla de la siguiente manera:

create_table :things do |t| 
  t.belongs_to :author, references: :users 
end 

Nota: la schema_plusgema en su totalidad no es compatible con los rieles 5+, pero esta gema es ofrecida por la gema schema_auto_foreign_keys (parte de schema_plus) que es compatible con los rieles 5.


28
y si está usando create_table:t.references :author, references: :users
— Michael Radionov

2
Agregar el comentario de @ MichaelRadionov a su respuesta lo haría perfecto.
— toxaq

2
He estado mirando la fuente de Rails 4.1, y no puedo encontrar ninguna evidencia que :referencesrealmente haga algo.
— jes5199

1
Sí, tienes razón, he estado usando la schema_plusgema durante años, y en realidad está agregando esa funcionalidad. Edité mi respuesta en consecuencia.
— nathanvda

2
En Rails 6, parece que la sintaxis t.references :col_name, references: other_table_namefunciona sin instalar gemas adicionales.
— Qqwy

51

Si no está utilizando una clave foránea, no importa cuál sea el nombre real de la tabla de la otra tabla.

add_reference :posts, :author

A partir de Rails 5 , si está utilizando una clave externa, puede especificar el nombre de la otra tabla en las opciones de clave externa. (ver https://github.com/rails/rails/issues/21563 para discusión)

add_reference :posts, :author, foreign_key: {to_table: :users}

Antes de Rails 5, debe agregar la clave externa como un paso separado:

add_foreign_key :posts, :users, column: :author_id

12
to_table es la forma pluralizada:{to_table: :users}
— hoffmanc

-3

alias_attribute (new_name, old_name) es muy útil. Simplemente cree su modelo y la relación:

rails g model Post title user:references

luego edite el modelo y agregue un alias de atributo con

alias_attribute :author, :user

Después de eso podrás ejecutar cosas como

Post.new(title: 'My beautiful story', author: User.first)

1
esto no funciona cuando necesita definir múltiples referencias a otro modelo, por ejemplo, publicación (autor, editor)
— ultrajohn
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.