【问题标题】:Tricky active record relationships - polymorphic bi-directional self-referential棘手的活动记录关系 - 多态双向自引用
【发布时间】:2009-02-11 10:32:09
【问题描述】:

您将如何对出版物(文章、书籍、章节等)的引用和引用建模?

出版物可以是一篇文章、一本书或一章,它有许多对其他出版物的引用,其他出版物也引用它(称为这些引文)

我需要能够列出出版物之间的关系:出版物中的引用以及其他出版物对该出版物的引用

我最初的理解是,这将是一种处理不同类型出版物的多态关系,并且需要双向自连接。

我的努力

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

我觉得这有点令人困惑,所以任何有助于澄清它的建议都会很棒。甚至对象和字段命名建议。

[我问了这个问题的不太清楚的版本here。]

我也可能需要使用has many through 因为我需要破坏关系的能力

【问题讨论】:

    标签: sql ruby-on-rails activerecord


    【解决方案1】:

    这是一个使用单表继承的自引用关系的解决方案。使用这些命令来创建应用程序:

    $ 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">]
    

    【讨论】:

    • 对其他人稍加注意:推荐有两个卢比
    【解决方案2】:

    这是一个不对发布使用单表继承的解决方案。这意味着有文章、书籍和章节表,而不是一个出版物表。以下是创建应用程序要运行的命令:

    $ 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">]   
    

    【讨论】:

      【解决方案3】:

      我在http://github.com/francois/so-536261/tree/master有一个不完整的答案

      基本上,数据库架构确实支持您的用例,但 ActiveRecord 不支持。该解决方案可能会涉及使用 sql 查找或其他技巧。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多