Adicione uma migração de coluna de referência no Rails 4

310

Um usuário tem muitos envios. Quero adicionar uma coluna à uploadstabela que referencia o arquivo user. Como deve ser a migração?

Aqui está o que eu tenho. Não tenho certeza se devo usar (1) :user_id, :intou (2) :user, :references. Eu nem tenho certeza se (2) funciona. Apenas tentando fazer isso da maneira "trilhos".

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

Pergunta relevante, exceto para o Rails 3. Migrações do Rails 3: Adicionando coluna de referência?

Don P
fonte

Respostas:

707

Rails 4.x

Quando você já tem users e uploadstabelas e deseja adicionar um novo relacionamento entre eles.

Tudo que você precisa fazer é: basta gerar uma migração usando o seguinte comando:

rails g migration AddUserToUploads user:references

O que criará um arquivo de migração como:

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

Em seguida, execute a migração usando rake db:migrate. Essa migração cuidará da adição de uma nova coluna denominada user_idà uploadstabela (referenciando a idcoluna na userstabela). Além disso, também adicionará um índice na nova coluna.

UPDATE [Para Rails 4.2]

Não é possível confiar nos Rails para manter a integridade referencial; bancos de dados relacionais vêm em nosso socorro aqui. O que isso significa é que podemos adicionar restrições de chave estrangeira no próprio nível do banco de dados e garantir que o banco de dados rejeite qualquer operação que viole a integridade referencial definida. Como o @infoget comentou, o Rails 4.2 é fornecido com suporte nativo a chaves estrangeiras (integridade referencial) . Não é necessário, mas você pode adicionar uma chave estrangeira (como é muito útil) à referência que criamos acima.

Para adicionar chave estrangeira a uma referência existente , crie uma nova migração para adicionar uma chave estrangeira:

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

Para criar uma referência totalmente nova com uma chave estrangeira (no Rails 4.2) , gere uma migração usando o seguinte comando:

rails g migration AddUserToUploads user:references

que criará um arquivo de migração como:

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

Isso adicionará uma nova chave estrangeira à user_idcoluna da uploadstabela. A chave referencia a idcoluna na userstabela.

NOTA: Além de adicionar uma referência, você ainda precisará criar uma referência primeiro e depois a chave estrangeira ( você pode optar por criar uma chave estrangeira na mesma migração ou em um arquivo de migração separado ). O Active Record suporta apenas chaves estrangeiras de coluna única e somente atualmente mysql, mysql2e os PostgreSQLadaptadores são suportados. Não tente fazer isso com outros adaptadores como sqlite3, etc. Consulte Guias do Rails: Chaves estrangeiras para sua referência.

Kirti Thorat
fonte
8
Em muitos casos, é bom adicionar chave estrangeira também. add_foreign_key (Rails 4.2)
poerror
18
Eu acredito que você pode fazer tudo em uma linha: add_reference: envios,: usuários, índice: verdade, foreign_key: @KirtiThorat verdade
user1801879
32
Agora, se você usar a sintaxe especial do gerador para migrações, o Rails 4.2 criará automaticamente a migração correta com restrições de chave estrangeira incluídas. rails g migration AddUserToUploads user:referencesproduz add_reference :uploads, :user, index: true, foreign_key: truena migração apropriada.
Jrhorn424 27/07/2015
10
Use em ...index: true, foreign_key: truevez o linha add_foreign_key.
Washington Botelho
2
Por que precisamos de ambos foreign_keye t.reference? Não é t.referenceessencialmente equivalente a foriegn_key+ index?
geoboy
188

Trilhos 5

Você ainda pode usar este comando para criar a migração:

rails g migration AddUserToUploads user:references

A migração parece um pouco diferente de antes, mas ainda funciona:

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

Note que é :user, não:user_id

Espelho318
fonte
2
Para classes espaçadas por nome, como em Local::Uservez de Userfazer algo como rails g migration AddLocalUserToUploads user:references.
21816 Ka Mok
3
isso adiciona automaticamente:index
Saravanabalagi Ramachandran 1/16
4
@Zeke Sim, executar a migração e verificar o seu esquema, ele deve dizer algo comot.index ["user_id"], name: "index_uploads_on_user_id", using: :btree
Mirror318
1
sim, I tem um "índice existe" erro quando i adicionados manualmente a add_index em migração: P @ Mirror318
Saravanabalagi Ramachandran
2
Também devemos adicionar belongs_to :userna Uploadclasse, para que possamos usar upload.userpara obter a instância do usuário.
Wit
17

se você gosta de outra abordagem alternativa com upe downmétodo, tente o seguinte:

  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
fonte
9

[Usando o Rails 5]

Gere migração:

rails generate migration add_user_reference_to_uploads user:references

Isso criará o arquivo de migração:

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

Agora, se você observar o arquivo de esquema, verá que a tabela de uploads contém um novo campo. Algo como: t.bigint "user_id"ou t.integer "user_id".

Migrar banco de dados:

rails db:migrate
vantagem
fonte
1
Esta resposta parece estar duplicada da resposta do @ Mirror318. Comente a resposta acima, se achar que algo está faltando. Obrigado.
Habib M.
8

Outra sintaxe de fazer a mesma coisa é:

rails g migration AddUserToUpload user:belongs_to
Nadeem Yasin
fonte
7

Apenas para documentar se alguém tem o mesmo problema ...

Na minha situação eu tenho usado :uuidcampos, e as respostas acima não trabalho para o meu caso, porque trilhos 5 estão criando uma coluna usando :bigintvez :uuid:

add_column :uploads, :user_id, :uuid
add_index :uploads, :user_id
add_foreign_key :uploads, :users
Bruno Casali
fonte
Também está muito mais claro o que está acontecendo. Mas sim, o UUID deve ser padrão agora.
hadees 02/03/19
2

Crie um arquivo de migração

rails generate migration add_references_to_uploads user:references

Nome da chave estrangeira padrão

Isso criaria uma coluna user_id na tabela de uploads como uma chave estrangeira

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

modelo de usuário:

class User < ApplicationRecord
  has_many :uploads
end

modelo de upload:

class Upload < ApplicationRecord
  belongs_to :user
end

Personalizar nome da chave estrangeira:

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

Isso criaria uma coluna author_id nas tabelas de uploads como a chave estrangeira.

modelo de usuário:

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

modelo de upload:

class Upload < ApplicationRecord
  belongs_to :user
end
Clint Clinton
fonte