Migración de rieles: t.references con nombre alternativo?

121

Entonces tengo una create_table como esta para Cursos en una escuela:

create_table :courses do |t|
  t.string :name
  t.references :course
  t.timestamps
end

pero quiero que haga referencia a otros dos cursos como:

has_many :transferrable_as # A Course
has_many :same_as          # Another Course

¿Puedo decir lo siguiente?

t.references :transferrable_as, :as=> :course
el espejo
fuente

Respuestas:

161

Puede hacer todo esto en la migración inicial / definición de columna (al menos actualmente en Rails 5):

t.references :transferable_as, index: true, foreign_key: {to_table: :courses}
t.references :same_as, index: true, foreign_key: {to_table: :courses}
Ryan
fuente
10
Esto funciona en Rails 5.1 y ninguna de las otras sugerencias lo hace. Es mucho más limpio y se siente bien.
stephenmurdoch
2
Utilizo Rails 5.1.4 pero no funciona. Cuando especifico una foreign_keyopción en la creación de la tabla de esta manera, se genera un error que dice que la misma tabla que estoy creando no existe ... Entonces sospecho que no es realmente compatible con la API oficial.
Quv
3
También leí que indexya se agregó a las claves externas a partir de Rails stackoverflow.com/questions/39769981/…
Jonathan Reyes
98

Puedes hacerlo de esta manera:

create_table :courses do |t|
  t.string :name
  t.references :transferrable_as
  t.references :same_as
  t.timestamps
end

o usar t.belongs_tocomo alias parat.references

No puede agregar foreign_key: truea esas dos líneas de referencias. Si desea marcarlos como claves externas en el nivel de la base de datos, debe realizar una migración con esto:

add_foreign_key :courses, :courses, column: :transferrable_as_id
add_foreign_key :courses, :courses, column: :same_as_id

Actualizar

En Rails 5.1 y superior, puede agregar la clave externa en la migración en el create_tablebloque de esta manera:

create_table :courses do |t|
  t.string :name
  t.references :transferrable_as, foreign_key: { to_table: 'courses' }
  t.references :same_as, foreign_key: { to_table: 'courses' }
  t.timestamps
end
Toby 1 Kenobi
fuente
5
La parte de no poder agregar foreign_key: truelíneas a las referencias fue lo que me hizo tropezar. Agregar add_foreign_keyy especificar el nombre de la columna para esos hizo el truco.
Matthew Clark
¿Funciona esto fuera de la caja en Rails? Según stackoverflow.com/a/22384289/239657 , esto requiere la schema_plusgema. Los documentos add_reference de Rails no mencionan opciones de: referencias.
Beni Cherniavsky-Paskin
1
No estoy siguiendo para qué es la references:opción (a diferencia de, t.references¿no sería eso solo relevante en el nivel del modelo, con las consideraciones de Foreign_key siendo atendidas por add_foreign_key?)
MCB
1
@MCB t.referencesdice "agregue un campo a esta tabla que sea la clave principal de otra tabla". La references:opción le dice de qué tabla es una clave primaria (necesaria si no está claro por el nombre del campo). La add_foreign_keyfunción le dice a la base de datos que aplique la integridad referencial aquí.
Toby 1 Kenobi
2
@MCB después de todo este tiempo me doy cuenta de que tenías razón todo el tiempo. Su primer comentario anterior es exactamente correcto: las add_foreign_keylíneas se encargan de informar a la base de datos qué es una clave externa de qué. El references:parámetro no hace nada.
Toby 1 Kenobi
13

Creo que este hilo tiene una forma diferente más de Rails: Scaffolding ActiveRecord: dos columnas del mismo tipo de datos

En la migración:

t.pertenece_a: transferible_as

t.pertenece_a: mismo_que

el espejo
fuente
1
pero, ¿cómo sabe la base de datos a qué clave externa vincular la tabla? Estoy intentando esto con la base de datos de Postgres y me está dando un error PG::UndefinedTable: ERRORal intentar agregar una restricción de clave externa a una tabla que no existe.
Toby 1 Kenobi
En caso de que alguien se lo pregunta, belongs_toes sólo un alias para referencesy por lo tanto tiene la misma funcionalidad exacta.
Jason Swett
11

Como respuesta adicional a esta pregunta, el modelo debe tener la siguiente línea para completar la asociación:

    belongs_to :transferrable_as, class_name: "Course"
    belongs_to :same_as, class_name: "Course"
Diego Díaz de Berenguer
fuente
3

No creo que referencesacepte la :asopción, pero puede crear sus columnas manualmente ...

create_table :courses do |t| 
  t.string  :name 
  t.integer :course1_id
  t.integer :course2_id 
  t.timestamps 
end 
Ju Nogueira
fuente