Określanie nazwy kolumny w migracji „odwołań”

124

Chcę zrobić migrationw Railsach odwołanie do innej tabeli. Zwykle zrobiłbym coś takiego:

add_column :post, :user, :references

Spowoduje to utworzenie kolumny o nazwie user_idw poststabeli. Ale co jeśli zamiast tego user_idchcę czegoś takiego author_id? Jak mogę to zrobić?

caarlos0
źródło

Odpowiedzi:

59

Zrób to ręcznie:

add_column :post, :author_id, :integer

ale teraz, kiedy tworzysz instrukcję should_to, będziesz musiał ją zmodyfikować, więc teraz musisz wywołać

def post
    belongs_to :user, :foreign_key => 'author_id'
end
mschultz
źródło
1
Czy nie muszę dodawać żadnego indeksu?
caarlos0
1
Tak, musisz utworzyć indeks podczas migracji.
Tom Harrison,
1
Kody Railsowe - tak naprawdę domyślnie nie używają indeksów. Teraz, jeśli chcesz indeksów (które są świetnym pomysłem - pomimo tego, że szyny całkowicie je zignorują), to z pewnością możesz je dodać. Będziesz chciał zapoznać się z przewodnikiem, do którego odsyłam, aby uzyskać więcej informacji na temat migracji w ogóle, a możesz nawet skończyć umieszczając wywołanie kodu SQL bezpośrednio w migracji. Powiedziałbym, że zignoruj ​​to, ponieważ nie jest to normalna część railsów, uzyskasz z tego 0 wydajności, ponieważ domyślne zapytania SQL generowane przez railsy nie wykorzystują tego. link
mschultz
hmm rozumiem. Dziękuję Ci bardzo!
caarlos0
używając schema_plusgem, t.references :category, index: true, foreign_key: true, references: :match_categoriesdziałał również dla mnie w pliku migracyjnym.
elquimista
251

Do szyn 5+

Definicja początkowa:

Jeśli definiowania Posttabeli wzorcowej, można ustawić references, indexa foreign_keyw jednym wierszu:

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

Aktualizuj istniejącą:

Jeśli dodajesz odniesienia do istniejącej tabeli, możesz to zrobić:

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

Uwaga: wartość domyślna indexto true.

Sheharyar
źródło
Czy początkowa definicja dopuszcza wartości null? Jeśli nie, czy znasz alternatywę dopuszczającą wartość null?
Vorpulus Lyphane
5
Ta definicja pozwala nulls. Aby im nie pozwolić, dodaj zwykłą opcję null: false.
Ashitaka
Dzięki. Myślę, że w przypadku „Definicji początkowej” wyrażenie „index: true” nie jest konieczne. Otrzymuję tę samą zmianę schematu z lub bez niej. Nieważne; właśnie zobaczyłem twoją notatkę na końcu.
Joey
Dzięki, właśnie tego szukałem!
Philippe B.
250

W Railsach 4.2+ możesz także ustawić klucze obce w bazie danych, co jest świetnym pomysłem .

W przypadku prostych skojarzeń można to zrobić również podczas t.referencesdodawania foreign_key: true, ale w tym przypadku będziesz potrzebować dwóch wierszy.

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

# The model
belongs_to :author, class_name: "User"
ecoologic
źródło
2
Dzięki, ale pytanie jest oznaczone tagiem Rails3, z przyjemnością pomogę
ecoologic
2
Ooh, nie zauważyłem tego. Cóż, bardzo mi pomogło. :)
bonh
2
Prawie straciłem nadzieję, kiedy to zobaczyłem! Dziękuję @ecoologic!
Dan Williams
2
@ecoologic, tylko jedna rzecz, którą możesz chcieć dodać, add_foreign_key to tylko rails 4.2+. ;)
Dan Williams
4
Nie jestem pewien, czy potrzebujesz references: :usersopcji w add_referencerozmowie. Nie widzę tego udokumentowanego w dokumentach i wydaje się, że działa po mojej stronie bez tego.
jakecraige
87

W rails 4, używając postgresql i gem schema_plus , możesz po prostu napisać

add_reference :posts, :author, references: :users

Spowoduje to utworzenie kolumny author_id, do której poprawnie odwołuje się users(id).

A w swoim modelu piszesz

belongs_to :author, class_name: "User"

Uwaga, podczas tworzenia nowej tabeli możesz zapisać ją w następujący sposób:

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

Uwaga: schema_plusklejnot w całości nie jest kompatybilny z railsami 5+, ale taką funkcjonalność oferuje gem schema_auto_foreign_keys (część schema_plus), który jest kompatybilny z railsami 5.

nathanvda
źródło
28
a jeśli używasz create_table:t.references :author, references: :users
Michael Radionov
2
Dodanie komentarza @ MichaelRadionov do swojej odpowiedzi sprawiłoby, że byłaby doskonała.
toxaq
2
Patrzyłem na źródło Rails 4.1 i nie mogę znaleźć żadnych dowodów, które :referencesfaktycznie coś robią.
jes5199
1
Tak, masz rację, używam tego schema_plusklejnotu od wieków i tak naprawdę dodaje on tę funkcjonalność. Odpowiednio zredagowałem odpowiedź.
nathanvda
2
W Rails 6 wygląda na to, że składnia t.references :col_name, references: other_table_namedziała bez instalowania dodatkowych klejnotów.
Qqwy
51

Jeśli nie używasz klucza obcego, nie ma znaczenia, jaka jest rzeczywista nazwa drugiej tabeli.

add_reference :posts, :author

Począwszy od Rails 5 , jeśli używasz klucza obcego, możesz określić nazwę innej tabeli w opcjach klucza obcego. (patrz https://github.com/rails/rails/issues/21563 do dyskusji)

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

Przed Railsami 5 należy dodać klucz obcy jako oddzielny krok:

add_foreign_key :posts, :users, column: :author_id
jes5199
źródło
12
to_table jest formą liczby mnogiej:{to_table: :users}
hoffmanc
-3

alias_attribute (nowa_nazwa, stara_nazwa) jest bardzo przydatna. Po prostu stwórz swój model i relację:

rails g model Post title user:references

następnie edytuj model i dodaj alias atrybutu za pomocą

alias_attribute :author, :user

Po tym będziesz mógł uruchamiać takie rzeczy jak

Post.new(title: 'My beautiful story', author: User.first)
sekmo
źródło
1
to nie działa, gdy trzeba zdefiniować wiele odniesień do innego modelu, np. post (autor, redaktor)
ultrajohn