Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tricky active record relationships - polymorphic bi-directional self-referential

How would you model the references and citations to publications (articles, books, chapters, etc...)?

A publication can be an article, book or a chapter and it has many references to other publications and other publications refer to it (call these citations)

I need to be able to list the relationships among the publications: The references in a publication and the citations from other publications to this publication

My initial understanding is that this would be a polymorphic relationship to handle the different types of publications and that it would require a bidirectionalself join.

My stab at it

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

I find this a bit confusing so any suggestions that would help clarify it would be great. Even object and field naming suggestions.

[I asked a less clear version of this question here.]

I also probably need to use has many through because I will need the ability to destroy the relationship

like image 922
srboisvert Avatar asked Feb 11 '09 10:02

srboisvert


1 Answers

Here's a solution using a self-referential relationship using single table inheritance. Use these commands to create the app:

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

The setup the relationships this way:

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

Now we can create the DB and try it out from the console:

$ 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">]
like image 166
pjb3 Avatar answered Oct 04 '22 12:10

pjb3