Migração de Rails: t.references com nome alternativo?

121

Portanto, tenho uma create_table como esta para Cursos em uma Escola:

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

mas eu quero fazer referência a dois outros cursos como:

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

Posso dizer o seguinte?

t.references :transferrable_as, :as=> :course
o espelho
fonte

Respostas:

161

Você pode fazer tudo isso na migração inicial / definição de coluna (pelo menos atualmente no 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
fonte
10
Isso funciona no Rails 5.1 e nenhuma das outras sugestões funciona. É muito mais limpo e parece certo.
stephenmurdoch
2
Eu uso Rails 5.1.4 mas não funciona. Quando eu especifico uma foreign_keyopção na criação da tabela desta forma, surge um erro dizendo que a própria tabela que estou criando não existe ... Portanto, suspeito que ela não seja realmente suportada pela API oficial.
Quv
3
Eu também li que indexjá foi adicionado às chaves estrangeiras em Rails stackoverflow.com/questions/39769981/…
Jonathan Reyes
98

Você pode fazer desta forma:

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

ou usando t.belongs_tocomo um alias parat.references

Você não pode adicionar foreign_key: truea essas duas linhas de referência. Se você deseja marcá-los como chaves estrangeiras no nível do banco de dados, você precisa fazer uma migração com isto:

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

Atualizar

No Rails 5.1 e superior você pode adicionar a chave estrangeira na migração no create_tablebloco assim:

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
fonte
5
A parte de não ser capaz de adicionar foreign_key: trueàs linhas de referência era o que estava me enganando. Adicionar add_foreign_keye especificar o nome da coluna para eles resolveu.
Matthew Clark
Isso funciona fora da caixa no Rails? De acordo com stackoverflow.com/a/22384289/239657 , isso requer a schema_plusgema. Os documentos add_reference do Rails não mencionam as opções a: reference.
Beni Cherniavsky-Paskin de
1
Não estou seguindo para que references:serve a opção (ao contrário de que t.referencesisso não seria relevante apenas no nível do modelo, com as considerações de Foreign_key sendo feitas por add_foreign_key?
MCB
1
@MCB t.referencesdiz "adicione um campo a esta tabela que é a chave primária de outra tabela." A references:opção informa de qual tabela é uma chave primária (necessária se não estiver clara pelo nome do campo). A add_foreign_keyfunção diz ao banco de dados para impor integridade referencial aqui.
Toby 1 Kenobi de
2
@MCB depois de todo esse tempo eu percebi que você estava certo o tempo todo. Seu primeiro comentário acima está exatamente correto - as add_foreign_keylinhas têm o cuidado de informar ao banco de dados o que é uma chave estrangeira de quê. O references:parâmetro não está fazendo nada.
Toby 1 Kenobi
13

Eu acho que este tópico tem um jeito diferente mais Rails: Scaffolding ActiveRecord: duas colunas do mesmo tipo de dados

Na migração:

t.belongs_to: transferrable_as

t.belongs_to: same_as

o espelho
fonte
1
mas como o banco de dados sabe a qual chave estrangeira vincular a tabela? Estou tentando fazer isso com o banco de dados Postgres e ele está me dando um erro, PG::UndefinedTable: ERRORele está tentando adicionar uma restrição de chave estrangeira a uma tabela que não existe.
Toby 1 Kenobi
Caso alguém esteja se perguntando, belongs_toé apenas um apelido para referencese tem exatamente a mesma funcionalidade.
Jason Swett
11

Como uma resposta adicional a esta pergunta - o modelo deve ter a seguinte linha para completar a associação:

    belongs_to :transferrable_as, class_name: "Course"
    belongs_to :same_as, class_name: "Course"
Diego Diaz de Berenguer
fonte
3

Acho que não referencesaceita a :asopção, mas você pode criar suas colunas manualmente ...

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