2009-02-11 4 views
8

Wie würden Sie die Referenzen und Zitate zu Publikationen (Artikel, Bücher, Kapitel, etc ...) modellieren? Eine Publikation kann ein Artikel, ein Buch oder ein Kapitel sein und es viele Verweise auf andere Publikationen und andere Publikationen darauf verweisen (nennen diese Zitate)Tricky aktive Datensatzbeziehungen - polymorphe bidirektionale selbstreferentielle

Ich muss in der Lage, zur Liste der Beziehungen zwischen den Publikationen

hat : Die Referenzen in einer Veröffentlichung und die Zitate aus anderen Publikationen zu dieser Veröffentlichung

Mein erstes Verständnis ist, dass dies eine polymorphe Beziehung sein würde, um die verschiedenen Arten von Publikationen zu behandeln, und dass es eine bidirektionale Selbstbeitritt erfordern würde.

Mein Stab an sie

Publication 
belongs_to :writing, :polymorphic =>true 
has_and_belongs_to_many :references 
    :class_name => "Publication" 
    :join_table => 'reference_citation' 
    :foreign_key => 'reference_id' 
    :foreign_key => 'citation_id' 

Book, Chapter, Article all have: 
has_many :publications :as =>writing 

Ich finde das ein bisschen verwirrend so irgendwelche Vorschläge, die es toll wäre zu klären helfen würde. Sogar Vorschläge für die Benennung von Objekten und Feldern.

[fragte ich eine weniger klare Version dieser Frage here.]

Ich brauche auch wahrscheinlich hat durch viele verwenden, weil ich die Fähigkeit benötigt, um die Beziehung

Antwort

12

Hier ist eine Lösung, die eine selbstbezüglicher Beziehung mit einzelner Tabelle mit Erbe.Verwenden Sie diese Befehle, um die App zu erstellen:

$ rails myproject 
$ cd myproject 
$ script/generate model publication type:string name:string 
$ script/generate model citation publication_id:integer reference_id:integer 

Der Aufbau der Beziehungen auf diese Weise:

class Publication < ActiveRecord::Base 
    has_many :citations 
    has_many :cited_publications, :through => :citations, :source => :reference 
    has_many :references, :foreign_key => "reference_id", :class_name => "Citation" 
    has_many :refered_publications, :through => :references, :source => :publication 
end 

class Citation < ActiveRecord::Base 
    belongs_to :publication 
    belongs_to :reference, :class_name => "Publication" 
end 

class Article < Publication 
end 

class Book < Publication 
end 

class Chapter < Publication 
end 

Jetzt können wir den DB erstellen und versuchen, es aus der Konsole heraus:

$ rake db:migrate 
$ script/console 
Loading development environment (Rails 2.2.2) 
>> a = Article.create!(:name => "Article") 
=> #<Article id: 1, ...> 
>> b = Book.create!(:name => "Book") 
=> #<Book id: 2, ...> 
>> a.citations.create(:reference => b) 
=> #<Citation id: 1, publication_id: 1, reference_id: 2, created_at: "2009-02-15 14:13:15", updated_at: "2009-02-15 14:13:15"> 
>> a.citations 
=> [#<Citation id: 1, ...>] 
>> a.references 
=> [] 
>> b.citations 
=> [] 
>> b.references 
=> [#<Citation id: 1, publication_id: 1, reference_id: 2, created_at: "2009-02-15 14:13:15", updated_at: "2009-02-15 14:13:15">]  
>> a.cited_publications 
=> [#<Book id: 2, type: "Book", name: "Book", created_at: "2009-02-15 14:11:00", updated_at: "2009-02-15 14:11:00">] 
>> a.refered_publications 
=> [] 
>> b.cited_publications 
=> [] 
>> b.refered_publications 
=> [#<Article id: 1, type: "Article", name: "Article", created_at: "2009-02-15 14:10:51", updated_at: "2009-02-15 14:10:51">] 
+1

Nur ein wenig Vorsicht für andere: bezeichnet hat zwei Rs – srboisvert

1

Ich habe eine unvollständige Antwort zu zerstören über um http://github.com/francois/so-536261/tree/master

Grundsätzlich unterstützt das DB-Schema Ihren Anwendungsfall, aber ActiveRecord nicht. Die Lösung wird wahrscheinlich die Verwendung von find by sql oder anderen Tricks beinhalten.

5

Hier ist eine Lösung, die für die Publikationen keine Tabellenvererbung verwendet. Das bedeutet, dass es anstelle einer Publikationstabelle Artikel, Bücher und Kapiteltische gibt. Hier sind die Befehle ausführen, um die App zu erstellen:

$ rails myproject 
$ cd myproject 
$ script/generate model book name:string 
$ script/generate model chapter name:string 
$ script/generate model article name:string 
$ script/generate model citation publication_type:string publication_id:integer reference_type:string reference_id:integer 

Erstellen Sie diese Datei in lib/acts_as_publication.rb:

module ActsAsPublication 
    def self.included(base) 
    base.extend(ClassMethods) 
    end 
    module ClassMethods 
    def acts_as_publication 
     has_many :citations, :as => :publication 
     has_many :references, :as => :reference, :class_name => "Citation"  
    end 
    end 
end 

Erstellen Sie diese Datei in config/initializers/acts_as_publication.rb:

ActiveRecord::Base.send(:include, ActsAsPublication) 

Dann, dass rufen in jedem Modell , Artikel, Buch und Kapitel, so:

class Article < ActiveRecord::Base 
    acts_as_publication 
end 

Dann fügen Sie diese Beziehungen in app/models/citation.rb:

class Citation < ActiveRecord::Base 
    belongs_to :publication, :polymorphic => true 
    belongs_to :reference, :polymorphic => true 
end 

Jetzt können wir die DB erstellen und versuchen, es aus der Konsole heraus:

$ rake db:migrate 
$ script/console 
Loading development environment (Rails 2.2.2) 
>> a = Article.create!(:name => "a") 
=> #<Article id: 1, ...> 
>> b = Article.create!(:name => "b") 
=> #<Article id: 2, ...> 
>> Citation.create!(:publication => a, :reference => b) 
=> #<Citation id: 1, publication_type: "Article", publication_id: 1, reference_type: "Article", reference_id: 2, created_at: "2009-02-15 13:14:27", updated_at: "2009-02-15 13:14:27"> 
>> a.citations 
=> [#<Citation id: 1, ...>] 
>> a.references 
=> [] 
>> b.citations 
=> [] 
>> b.references 
=> [#<Citation id: 1, ...>] 
>> Book.create!(:name => "foo") 
=> #<Book id: 1, name: "foo", created_at: "2009-02-15 13:18:23", updated_at: "2009-02-15 13:18:23"> 
>> a.citations.create(:reference => Book.first) 
=> #<Citation id: 2, publication_type: "Article", publication_id: 1, reference_type: "Book", reference_id: 1, created_at: "2009-02-15 13:18:52", updated_at: "2009-02-15 13:18:52"> 
>> Book.first.references 
=> [#<Citation id: 2, ...>] 
>> a.citations 
=> [#<Citation id: 1, publication_type: "Article", publication_id: 1, reference_type: "Article", reference_id: 2, created_at: "2009-02-15 13:14:27", updated_at: "2009-02-15 13:14:27">, #<Citation id: 2, publication_type: "Article", publication_id: 1, reference_type: "Book", reference_id: 1, created_at: "2009-02-15 13:18:52", updated_at: "2009-02-15 13:18:52">]