sql - query - Relaciones de registro activas difíciles-poliforma bidireccional autorreferencial
rails generate model (3)
¿Cómo modelarías las referencias y citas de publicaciones (artículos, libros, capítulos, etc.)?
Una publicación puede ser un artículo, un libro o un capítulo y tiene muchas referencias a otras publicaciones y otras publicaciones hacen referencia a ella (llame a estas citas)
Necesito poder enumerar las relaciones entre las publicaciones: las referencias en una publicación y las citas de otras publicaciones a esta publicación
Mi comprensión inicial es que esta sería una relación polimórfica para manejar los diferentes tipos de publicaciones y que requeriría una unión bidireccional.
Mi puñalada
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
Encuentro esto un poco confuso por lo que cualquier sugerencia que pueda ayudar a aclararlo sería genial. Incluso sugerencias de nombres de objetos y campos.
[Solicité una versión menos clara de esta pregunta aquí .]
También es probable que necesite utilizar tiene muchos porque voy a necesitar la capacidad de destruir la relación
Tengo una respuesta incompleta en http://github.com/francois/so-536261/tree/master
Básicamente, el esquema DB admite su caso de uso, pero ActiveRecord no. La solución probablemente implicará el uso de find by sql u otros trucos.
Aquí hay una solución que no usa la herencia de tabla única para las publicaciones. Eso significa que hay artículos, libros y tablas de capítulos, en lugar de una tabla de publicaciones. Aquí están los comandos para ejecutar para crear la aplicación:
$ 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
Cree este archivo en 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
Cree este archivo en config/initializers/acts_as_publication.rb
:
ActiveRecord::Base.send(:include, ActsAsPublication)
Luego llame a eso en cada modelo, artículo, libro y capítulo, así:
class Article < ActiveRecord::Base
acts_as_publication
end
A continuación, agregue estas relaciones en la app/models/citation.rb
:
class Citation < ActiveRecord::Base
belongs_to :publication, :polymorphic => true
belongs_to :reference, :polymorphic => true
end
Ahora podemos crear el DB y probarlo desde la consola:
$ 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">]
Aquí hay una solución que usa una relación autorreferencial usando herencia de tabla única. Use estos comandos para crear la aplicación:
$ rails myproject
$ cd myproject
$ script/generate model publication type:string name:string
$ script/generate model citation publication_id:integer reference_id:integer
La configuración de las relaciones de esta manera:
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
Ahora podemos crear el DB y probarlo desde la consola:
$ 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">]