Menentukan nama kolom dalam migrasi "referensi"

124

Saya ingin membuat migrationdi Rails, mereferensikan tabel lain. Biasanya, saya akan melakukan sesuatu seperti:

add_column :post, :user, :references

Ini membuat kolom bernama user_iddalam poststabel. Tetapi bagaimana jika, alih-alih user_id, saya menginginkan sesuatu seperti itu author_id? Bagaimana saya bisa melakukan itu?

caarlos0
sumber

Jawaban:

59

Lakukan secara manual:

add_column :post, :author_id, :integer

tetapi sekarang, ketika Anda membuat pernyataan milik_to, Anda harus memodifikasinya, jadi sekarang Anda harus memanggil

def post
    belongs_to :user, :foreign_key => 'author_id'
end
mschultz.dll
sumber
1
Apakah saya tidak perlu menambahkan indeks apa pun?
caarlos0
1
Ya, Anda harus membuat indeks dalam migrasi.
Tom Harrison
1
Curang Rails - tidak benar-benar menggunakan indeks secara default. Sekarang jika Anda menginginkan indeks (yang merupakan ide bagus - terlepas dari kenyataan bahwa rails akan mengabaikannya sepenuhnya), Anda pasti dapat menambahkannya. Anda akan ingin melihat panduan yang saya tautkan untuk info lebih lanjut tentang migrasi secara umum, dan Anda bahkan mungkin akhirnya memasukkan kode SQL panggilan langsung dalam migrasi Anda. Saya akan mengatakan abaikan itu, karena ini bukan bagian normal dari rel, Anda akan mendapatkan 0 kinerja darinya, karena kueri SQL yang dihasilkan default dari rel tidak memanfaatkannya. tautan
mschultz
hmm mengerti. Terima kasih banyak!
caarlos0
menggunakan schema_pluspermata, t.references :category, index: true, foreign_key: true, references: :match_categoriesjuga berfungsi untuk saya dalam file migrasi.
elquimista
251

Untuk Rails 5+

Definisi Awal:

Jika Anda mendefinisikan Posttabel model Anda, Anda dapat mengatur references, indexdan foreign_keydalam satu baris:

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

Perbarui yang Ada:

Jika Anda menambahkan referensi ke tabel yang sudah ada, Anda bisa melakukan ini:

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

Catatan: Nilai default indexadalah benar.

Sheharyar
sumber
Apakah definisi awal memungkinkan nulls? Jika tidak, apakah Anda tahu alternatif nullable?
Vorpulus Lyphane
5
Definisi ini memungkinkan nulls. Untuk tidak mengizinkannya, tambahkan opsi biasa null: false.
Ashitaka
Terima kasih. Untuk "Definisi Awal", menurut saya "index: true" tidak diperlukan. Saya mendapatkan perubahan skema yang sama dengan atau tanpa itu. Lupakan; baru saja melihat catatan Anda di bagian akhir.
Joey
Terima kasih, inilah yang saya cari!
Philippe B.
250

Di Rails 4.2+ Anda juga dapat mengatur kunci asing di db, yang merupakan ide bagus .

Untuk asosiasi sederhana, ini juga dapat dilakukan dengan t.referencesmenambahkan foreign_key: true, tetapi dalam kasus ini Anda memerlukan dua baris.

# The migration
add_reference :posts, :author, index: true
add_foreign_key :posts, :users, column: :author_id

# The model
belongs_to :author, class_name: "User"
ekologi
sumber
2
Terima kasih, tetapi pertanyaannya adalah Rails3, dengan senang hati saya akan membantu
ekologi
2
Ooh, saya tidak menyadarinya. Yah, itu sangat membantu to.me. :)
bonh
2
Saya hampir putus asa saat melihat ini! Terima kasih @ecoologic!
Dan Williams
2
@ ecologic, hanya satu hal yang mungkin ingin Anda tambahkan, add_foreign_key hanya rel 4.2+. ;)
Dan Williams
4
Saya tidak yakin Anda memerlukan references: :usersopsi saat add_referencemenelepon. Saya tidak melihatnya didokumentasikan di dokumen dan tampaknya berfungsi di pihak saya tanpa itu.
jakecraige
87

Di rel 4, saat menggunakan postgresql dan permata schema_plus Anda cukup menulis

add_reference :posts, :author, references: :users

Ini akan membuat kolom author_id, yang mengacu dengan benar users(id).

Dan dalam model Anda, Anda menulis

belongs_to :author, class_name: "User"

Catatan, saat membuat tabel baru Anda dapat menuliskannya sebagai berikut:

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

Catatan: schema_plusgem secara keseluruhan tidak kompatibel dengan rails 5+, tetapi fungsionalitas ini ditawarkan oleh gem schema_auto_foreign_keys (bagian dari schema_plus) yang kompatibel dengan rails 5.

nathanvda
sumber
28
dan jika Anda menggunakan create_table:t.references :author, references: :users
Michael Radionov
2
Menambahkan komentar @ MichaelRadionov pada jawaban Anda akan membuatnya sempurna.
Toxaq
2
Saya telah melihat sumber Rails 4.1, dan saya tidak dapat menemukan bukti apa pun yang :referencesbenar - benar berfungsi.
jes5199
1
Ya, Anda benar, saya telah menggunakan schema_pluspermata itu selama berabad-abad, dan itu sebenarnya menambahkan fungsi itu. Saya mengedit jawaban saya sesuai.
nathanvda
2
Di Rails 6, sepertinya sintaksnya t.references :col_name, references: other_table_nameberfungsi tanpa memasang permata tambahan.
Qqwy
51

Jika Anda tidak menggunakan kunci asing, maka tidak masalah apa nama tabel sebenarnya dari tabel lain.

add_reference :posts, :author

Pada Rails 5 , jika Anda menggunakan kunci asing, Anda dapat menentukan nama tabel lain di opsi kunci asing. (lihat https://github.com/rails/rails/issues/21563 untuk diskusi)

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

Sebelum Rails 5, Anda harus menambahkan kunci asing sebagai langkah terpisah:

add_foreign_key :posts, :users, column: :author_id
jes5199
sumber
12
to_table adalah bentuk jamak:{to_table: :users}
hoffmanc
-3

alias_attribute (nama_baru, nama_lama) sangat berguna. Buat saja model Anda dan hubungannya:

rails g model Post title user:references

lalu edit model dan tambahkan alias atribut dengan

alias_attribute :author, :user

Setelah itu Anda akan dapat menjalankan hal-hal seperti

Post.new(title: 'My beautiful story', author: User.first)
sekmo
sumber
1
ini tidak berfungsi ketika Anda perlu mendefinisikan banyak referensi ke model lain, misalnya, posting (penulis, editor)
ultrajohn