Хитроумные отношения активной записи - полиморфная двунаправленная само-ссылка - PullRequest
8 голосов
/ 11 февраля 2009

Как бы вы смоделировали ссылки и цитаты на публикации (статьи, книги, главы и т. Д ...)?

Публикация может быть статьей, книгой или главой, и в ней много ссылок на другие публикации, и другие публикации ссылаются на нее (назовите эти цитаты)

Мне нужно иметь возможность перечислить отношения между публикациями: ссылки в публикации и цитаты из других публикаций к этой публикации

Мое первоначальное понимание состоит в том, что это будет полиморфное отношение для работы с различными типами публикаций и что для этого потребуется двунаправленное соединение.

Мой удар в это

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

Я нахожу это немного запутанным, поэтому любые предложения, которые помогут прояснить это, были бы полезны. Даже предложения по именованию объектов и полей.

[Я задал менее ясную версию этого вопроса здесь .]

Мне также, вероятно, нужно использовать много, потому что мне понадобится способность разрушать отношения

Ответы [ 3 ]

12 голосов
/ 15 февраля 2009

Вот решение, использующее самоссылочные отношения с использованием наследования одной таблицы. Используйте эти команды для создания приложения:

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

Настройка отношений следующим образом:

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

Теперь мы можем создать БД и попробовать ее из консоли:

$ 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">]
5 голосов
/ 15 февраля 2009

Вот решение, которое не использует наследование одной таблицы для публикаций. Это означает, что вместо одной таблицы публикаций есть таблицы статей, книг и глав. Вот команды, которые нужно запустить для создания приложения:

$ 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

Создать этот файл в 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

Создать этот файл в config/initializers/acts_as_publication.rb:

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

Затем назовите это в каждой модели, Статье, Книге и Главе следующим образом:

class Article < ActiveRecord::Base
  acts_as_publication
end

Затем добавьте эти отношения в app/models/citation.rb:

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

Теперь мы можем создать БД и попробовать ее из консоли:

$ 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">]   
1 голос
/ 11 февраля 2009

У меня есть неполный ответ на http://github.com/francois/so-536261/tree/master

По сути, схема БД поддерживает ваш вариант использования, но ActiveRecord - нет. Решение, вероятно, будет включать в себя поиск по sql или другие приемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...