Agregar una migración de columna de referencia en Rails 4

311

Un usuario tiene muchas cargas. Quiero agregar una columna a la uploadstabla que hace referencia a user. ¿Cómo debería ser la migración?

Aquí está lo que tengo. No estoy seguro de si debo usar (1) :user_id, :into (2) :user, :references. Ni siquiera estoy seguro si (2) funciona. Solo trato de hacer esto a la manera de "rieles".

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_column :uploads, :user_id, :integer
  end
end

Pregunta relevante a excepción de Rails 3. Migraciones de Rails 3: ¿Agregar columna de referencia?

Don P
fuente

Respuestas:

707

Carriles 4.x

Cuando ya tienes users y uploadsmesas y desea agregar una nueva relación entre ellos.

Todo lo que necesita hacer es: simplemente generar una migración con el siguiente comando:

rails g migration AddUserToUploads user:references

Lo que creará un archivo de migración como:

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_reference :uploads, :user, index: true
  end
end

Luego, ejecute la migración usando rake db:migrate. Esta migración se encargará de agregar una nueva columna llamada user_idauploads tabla (haciendo referencia a la idcolumna en la userstabla), ADEMÁS, también agregará un índice en la nueva columna.

ACTUALIZACIÓN [Para Rails 4.2]

No se puede confiar en los rieles para mantener la integridad referencial; bases de datos relacionales vienen a nuestro rescate aquí. Lo que eso significa es que podemos agregar restricciones de clave externa en el nivel de la base de datos y garantizar que la base de datos rechace cualquier operación que viole esta integridad referencial establecida. Como comentó @infoget, Rails 4.2 viene con soporte nativo para claves foráneas (integridad referencial) . No es obligatorio, pero es posible que desee agregar una clave externa (ya que es muy útil) a la referencia que creamos anteriormente.

Para agregar una clave externa a una referencia existente , cree una nueva migración para agregar una clave externa:

class AddForeignKeyToUploads < ActiveRecord::Migration
  def change
    add_foreign_key :uploads, :users
  end
end

Para crear una referencia completamente nueva con una clave foránea (en Rails 4.2) , genere una migración con el siguiente comando:

rails g migration AddUserToUploads user:references

que creará un archivo de migración como:

class AddUserToUploads < ActiveRecord::Migration
  def change
    add_reference :uploads, :user, index: true
    add_foreign_key :uploads, :users
  end
end

Esto agregará una nueva clave externa a la user_idcolumna de la uploadstabla. La clave hace referencia a la idcolumna en la userstabla.

NOTA: Esto es además de agregar una referencia, por lo que aún debe crear una referencia primero y luego una clave externa ( puede elegir crear una clave externa en la misma migración o en un archivo de migración separado ). Active Record solo admite claves foráneas de una sola columna y actualmente solo mysql, mysql2y los PostgreSQLadaptadores son compatibles. No intente esto con otros adaptadores como sqlite3, etc. Consulte las guías de Rails: claves externas para su referencia.

Kirti Thorat
fuente
8
En muchos casos, también es bueno agregar una clave externa. add_foreign_key (Rails 4.2)
poerror
18
Creo que puede hacer todo en una línea: add_reference: uploads,: user, index: true, foreign_key: true @KirtiThorat
user1801879
33
Ahora, si usa la sintaxis especial del generador para las migraciones, Rails 4.2 creará automáticamente la migración correcta con restricciones de clave externa incluidas. rails g migration AddUserToUploads user:referencesproduce add_reference :uploads, :user, index: true, foreign_key: trueen la migración adecuada.
jrhorn424
10
Use en su ...index: true, foreign_key: truelugar o línea add_foreign_key.
Washington Botelho
2
¿Por qué necesitamos ambos foreign_keyy t.reference? ¿No es t.referenceesencialmente equivalente a foriegn_key+ index?
geoboy
189

Carriles 5

Todavía puede usar este comando para crear la migración:

rails g migration AddUserToUploads user:references

La migración se ve un poco diferente a la anterior, pero aún funciona:

class AddUserToUploads < ActiveRecord::Migration[5.0]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

Tenga en cuenta que es :user, no:user_id

Espejo318
fuente
2
Para clases espaciadas por nombre, como en Local::Userlugar de Userhacer algo como rails g migration AddLocalUserToUploads user:references.
Ka Mok
3
¿esto agrega automáticamente:index
Saravanabalagi Ramachandran
44
@ Zeke Sí, ejecute la migración y verifique su esquema, debería decir algo comot.index ["user_id"], name: "index_uploads_on_user_id", using: :btree
Mirror318
1
sí, recibí un error de "índice existe" cuando agregué manualmente el add_index en la migración: P @ Mirror318
Saravanabalagi Ramachandran
2
También deberíamos agregar belongs_to :useren Uploadclase, para que podamos usar upload.userpara obtener la instancia de usuario.
Ingenio el
17

si desea otro enfoque upy downmétodo alternativos , pruebe esto:

  def up
    change_table :uploads do |t|
      t.references :user, index: true
    end
  end

  def down
    change_table :uploads do |t|
      t.remove_references :user, index: true
    end
  end
Kiry Meas
fuente
9

[Usando Rails 5]

Generar migración:

rails generate migration add_user_reference_to_uploads user:references

Esto creará el archivo de migración:

class AddUserReferenceToUploads < ActiveRecord::Migration[5.1]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

Ahora, si observa el archivo de esquema, verá que la tabla de cargas contiene un nuevo campo. Algo así como: t.bigint "user_id"o t.integer "user_id".

Migrar base de datos:

rails db:migrate
vantony
fuente
1
Esta respuesta parece ser un duplicado de la respuesta de @ Mirror318. Comente la respuesta anterior si cree que le falta algo. Gracias.
M. Habib
8

Otra sintaxis de hacer lo mismo es:

rails g migration AddUserToUpload user:belongs_to
Nadeem Yasin
fuente
7

Solo para documentar si alguien tiene el mismo problema ...

En mi situación, he estado usando :uuidcampos, y las respuestas anteriores no funcionan para mi caso, porque los rieles 5 están creando una columna usando en su :bigintlugar :uuid:

add_column :uploads, :user_id, :uuid
add_index :uploads, :user_id
add_foreign_key :uploads, :users
Bruno Casali
fuente
También está mucho más claro lo que está sucediendo. Pero sí, UUID debería ser estándar ahora.
Hadiz
2

Crear un archivo de migración

rails generate migration add_references_to_uploads user:references

Nombre de clave externa predeterminada

Esto crearía una columna user_id en la tabla de cargas como una clave foránea

class AddReferencesToUploads < ActiveRecord::Migration[5.2]
  def change
    add_reference :uploads, :user, foreign_key: true
  end
end

modelo de usuario:

class User < ApplicationRecord
  has_many :uploads
end

cargar modelo:

class Upload < ApplicationRecord
  belongs_to :user
end

Personalizar nombre de clave externa:

add_reference :uploads, :author, references: :user, foreign_key: true

Esto crearía una columna author_id en las tablas de cargas como la clave foránea.

modelo de usuario:

class User < ApplicationRecord
  has_many :uploads, foreign_key: 'author_id'
end

cargar modelo:

class Upload < ApplicationRecord
  belongs_to :user
end
Clint Clinton
fuente