Especificando o nome da coluna em uma migração de "referências"


124

Eu quero fazer um migrationno Rails, referenciando outra tabela. Normalmente, eu faria algo como:

add_column :post, :user, :references

Isso cria uma coluna nomeada user_idna poststabela. Mas e se, em vez de user_id, eu quiser algo assim author_id? Como eu posso fazer isso?

Respostas:


59

Faça manualmente:

add_column :post, :author_id, :integer

mas agora, quando você cria a instrução belongs_to, precisará modificá-la, então agora você deve chamar

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

1
Não tenho que adicionar nenhum índice?
precisa saber é o seguinte

1
Sim, você precisará criar um índice na migração.
Tom Harrison

1
Fraudes do Rails - ele realmente não usa índices por padrão. Agora, se você deseja índices (que são uma ótima idéia - apesar do fato de os trilhos os ignorarem completamente), você certamente pode adicioná-los. Você deve consultar o guia que eu vinculo para obter mais informações sobre migrações em geral e pode até acabar colocando o código SQL de chamada diretamente em sua migração. Eu diria que ignorá-lo, como não é uma parte normal dos trilhos, você obterá 0 desempenho dele, pois as consultas SQL geradas por padrão dos trilhos não tiram vantagem disso. link
mschultz 4/12/12

hmm entendido. Muito obrigado!
usar o seguinte código

usando schema_plusgem, t.references :category, index: true, foreign_key: true, references: :match_categoriestambém funcionou para mim no arquivo de migração.
27616 elquimista

251

Para Rails 5+

Definição inicial:

Se você estiver definindo sua Posttabela de modelos, poderá definir references, indexe foreign_keyem uma linha:

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

Atualização existente:

Se você estiver adicionando referências a uma tabela existente, poderá fazer o seguinte:

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

Nota: O valor padrão para indexé verdadeiro.


A definição inicial permitirá nulos? Caso contrário, você conhece a alternativa anulável?
Vorpulus Lyphane

5
Esta definição permite nulls. Para não permitir, adicione a opção usual null: false.
Ashitaka 27/11

Obrigado. Para a "Definição inicial", acho que o "índice: verdadeiro" não é necessário. Recebo a mesma alteração de esquema com ou sem ela. Deixa pra lá; acabei de ver sua nota no final.
Joey

Obrigado, é isso que eu estava procurando!
Philippe B.

250

No Rails 4.2+, você também pode definir chaves estrangeiras no banco de dados, o que é uma ótima idéia .

Para associações simples, isso também pode ser feito na t.referencesadição foreign_key: true, mas neste caso você precisará de duas linhas.

# 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
Obrigado, mas a questão é marcado Rails3, eu estou feliz em apenas ajuda fora
ecoologic

2
Ooh, eu não percebi isso. Bem, tem sido muito útil para o.me. :)
bonh

2
Eu quase tinha perdido a esperança quando vi isso! Obrigado @ecoologic!
Dan Williams

2
@ecoologic, apenas uma coisa que você pode querer adicionar, add_foreign_key é apenas o rails 4.2+. ;)
Dan Williams

4
Não sei se você precisa da references: :usersopção na add_referencechamada. Não o vejo documentado nos documentos e parece funcionar do meu lado sem ele.
jakecraige

87

No rails 4, ao usar o postgresql e a gema schema_plus, você pode simplesmente escrever

add_reference :posts, :author, references: :users

Isso criará uma coluna author_id, à qual corretamente se refere users(id).

E no seu modelo, você escreve

belongs_to :author, class_name: "User"

Observe que, ao criar uma nova tabela, você pode escrevê-la da seguinte maneira:

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

Nota: a schema_plusgema em sua totalidade não é compatível com os trilhos 5+, mas essa funcionalidade é oferecida pela gema schema_auto_foreign_keys (parte do schema_plus) que é compatível com os trilhos 5.


28
e se você está usando create_table:t.references :author, references: :users
Michael Radionov

2
Adicionar o comentário de @ MichaelRadionov à sua resposta o tornaria perfeito.
toxaq

2
Eu estive pesquisando a fonte do Rails 4.1 e não consigo encontrar nenhuma evidência que :referencesrealmente faça alguma coisa.
jes5199

1
Sim, você está certo, eu uso a schema_plusgema há muito tempo e, na verdade, ela está adicionando essa funcionalidade. Eu editei minha resposta de acordo.
Nathanvda

2
No Rails 6, parece que a sintaxe t.references :col_name, references: other_table_namefunciona sem a instalação de gemas extras.
Qqwy

51

Se você não estiver usando uma chave estrangeira, não importa qual seja o nome da tabela real da outra tabela.

add_reference :posts, :author

No Rails 5 , se você estiver usando uma chave estrangeira, poderá especificar o nome da outra tabela nas opções de chave estrangeira. (consulte https://github.com/rails/rails/issues/21563 para discussão)

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

Antes do Rails 5, você deveria adicionar a chave estrangeira como uma etapa separada:

add_foreign_key :posts, :users, column: :author_id

12
to_table é a forma pluralizada:{to_table: :users}
hoffmanc 11/02

-3

alias_attribute (new_name, old_name) é muito útil. Basta criar seu modelo e o relacionamento:

rails g model Post title user:references

edite o modelo e adicione um alias de atributo com

alias_attribute :author, :user

Depois disso, você poderá executar coisas como

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

1
Isto não funciona quando você precisa definir várias referências a um outro modelo, por exemplo, pós (autor, editor)
ultrajohn
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.