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?

caarlos0
fuente

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
mschultz
fuente
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.

Sheharyar
fuente
¿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"
ecoologico
fuente
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.

nathanvda
fuente
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
jes5199
fuente
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)
sekmo
fuente
1
esto no funciona cuando necesita definir múltiples referencias a otro modelo, por ejemplo, publicación (autor, editor)
ultrajohn