2009-05-24 3 views
48

Ho una classe di commento con un: foreign_key di post_id nella classe Post.Definizione di relazioni di chiavi esterne per i modelli di Rails

class Comment < ActiveRecord::Base 
    belongs_to :post, :class_name => "Post", :foreign_key => "post_id", :counter_cache => true 
    belongs_to :author, :class_name => "User", :foreign_key => "author_id" 
end 

Ma la mia migrazione CreateComments non definisce una chiave esterna a livello di database:

class CreateComments < ActiveRecord::Migration 
    def self.up 
    create_table :comments do |t| 
     t.column "post_id",  :integer, :default => 0, :null => false 
     t.column "author",  :string, :default => "", :limit => 25, :null => false 
     t.column "author_email", :string, :default => "", :limit => 50, :null => false 
     t.column "content",  :text,  :null => false 
     t.column "status",  :string, :default => "", :limit => 25, :null => false 
     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :comments 
    end 
end 

Invece post_id è una colonna integer semplice.

Quindi, sembra che questa relazione di chiave esterna esista solo nella mente di Rails, non a livello di database.

È corretto?

Inoltre, è necessario che il modello Post corrispondente dichiari anche la sua reciproca relazione di chiave esterna con Commenti utilizzando l'attributo: foreign_key o potrebbe essere omesso?

class Post < ActiveRecord::Base 
    set_table_name("blog_posts") 
    belongs_to :author, :class_name => "User", :foreign_key => 'author_id' 
    has_many :comments, :class_name => "Comment", 
    :foreign_key => 'post_id', :order => "created_at desc", :dependent => :destroy 
    has_many :categorizations 
    has_many :categories, :through => :categorizations 
    named_scope :recent, :order => "created_at desc", :limit => 5 

end 
+0

Condividi la tua sorpresa sul fatto che Rails non utilizzi chiavi esterne SQL. Rende difficile l'uso di strumenti non rotaiati sui DB. – Greg

+2

Rails segue la convenzione che "TUTTA la logica aziendale dovrebbe essere definita nell'applicazione" ... quindi utilizza DB solo come memoria "stupida". Nessuna chiave esterna, nessuna stored procedure, nessun vincolo (supportato in postgres per esempio). EDIT: Ho appena trovato questa risposta che dice lo stesso - http://stackoverflow.com/questions/8334602/need-to-create-a-foreign-key-when-creating-a-table-on-rails –

+1

https://github.com/matthuhiggins/proprietario – wberry

risposta

69

Il comportamento di default Rails è che la colonna utilizzato per contenere la chiave esterna su un modello è il nome dell'associazione con il suffisso _id aggiunto. L'opzione :foreign_key consente di impostare direttamente il nome della chiave esterna. Le associazioni tra i tuoi Post e Comment classi del modello dovrebbe essere simile a questo:

class Post < ActiveRecord::Base 
    has_many :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

— Si noti che non è necessario :class_name => "Post" nel modello Comment. Rails ha già quell'informazione. È necessario specificare solo :class_name e :foreign_key quando è necessario sostituire le convenzioni di Rails.

Hai ragione che Rails mantiene le relazioni con le chiavi esterne per te. Puoi applicarli nel livello del database se desideri aggiungendo vincoli di chiave esterna.

+0

Poiché la connessione foreign_key non è a livello di database e solo nelle guide. Se un record viene cancellato da Post, anche la riga associata nel commento verrà cancellata? Questo è un altro vantaggio nel mantenere foreign_key. Otterrò questo beneficio? –

+0

Se si desidera eliminare anche la colonna associata. Devi aggiungere 'dependent: destroy' alla fine della linea che hai scritto dell'associazione. – Lavika