Ruby on rails Rails中的双向多态连接模型?

Ruby on rails Rails中的双向多态连接模型?,ruby-on-rails,activerecord,ruby-on-rails-3,polymorphic-associations,Ruby On Rails,Activerecord,Ruby On Rails 3,Polymorphic Associations,我正在开发一个多站点CMS,它有一个站点间交叉发布的概念。多种类型的内容(文章、事件、Bios等)可以与许多站点相关联,并且站点可以有许多内容。内容片段和站点之间的多对多关联还必须支持每个相关内容项的两个公共属性——站点起源的概念(这是内容出现的原始站点吗?)以及“主要”和“次要”的概念给定关联站点上给定内容的内容状态 我的想法是创建一个称为ContentAssociation的多态性连接模型,但是我很难让多态性关联按照我预期的方式运行,我想知道我是否完全错了 以下是我对联接表和模型的设置: c

我正在开发一个多站点CMS,它有一个站点间交叉发布的概念。多种类型的内容(文章、事件、Bios等)可以与许多站点相关联,并且站点可以有许多内容。内容片段和站点之间的多对多关联还必须支持每个相关内容项的两个公共属性——站点起源的概念(这是内容出现的原始站点吗?)以及“主要”和“次要”的概念给定关联站点上给定内容的内容状态

我的想法是创建一个称为ContentAssociation的多态性连接模型,但是我很难让多态性关联按照我预期的方式运行,我想知道我是否完全错了

以下是我对联接表和模型的设置:

create_table "content_associations", :force => true do |t|
  t.string   "associable_type"
  t.integer  "associable_id"
  t.integer  "site_id"
  t.boolean  "primary_eligible"
  t.boolean  "secondary_eligible"
  t.boolean  "originating_site"
  t.datetime "created_at"
  t.datetime "updated_at"
end

class ContentAssociation < ActiveRecord::Base
  belongs_to :site
  belongs_to :associable, :polymorphic => true
  belongs_to :primary_site, :class_name => "Site", :foreign_key => "site_id" 
  belongs_to :secondary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :originating_site, :class_name => "Site", :foreign_key => "site_id"
end

class Site < ActiveRecord::Base
  has_many :content_associations, :dependent => :destroy 
  has_many :articles, :through => :content_associations, :source => :associable, :source_type => "Article"
  has_many :events, :through => :content_associations, :source => :associable, :source_type => "Event"

  has_many :primary_articles, :through => :content_associations, 
                              :source => :associable, 
                              :source_type => "Article", 
                              :conditions => ["content_associations.primary_eligible = ?" true]

  has_many :originating_articles, :through => :content_associations, 
                                  :source => :associable, 
                                  :source_type => "Article", 
                                  :conditions => ["content_associations.originating_site = ?" true]

  has_many :secondary_articles, :through => :content_associations, 
                                :source => :associable, 
                                :source_type => "Article", 
                                :conditions => ["content_associations.secondary_eligible = ?" true]
end

class Article < ActiveRecord::Base
  has_many :content_associations, :as => :associable, :dependent => :destroy
  has_one :originating_site, :through => :content_associations, 
                             :source => :associable, 
                             :conditions => ["content_associations.originating_site = ?" true]

  has_many :primary_sites, :through => :content_associations, 
                           :source => :associable
                           :conditions => ["content_associations.primary_eligible = ?" true]

  has_many :secondary_sites, :through => :content_associations, 
                             :source => :associable
                             :conditions => ["content_associations.secondary_eligible = ?" true]                         
end
还是这个

@site.primary_articles << @article
@article.primary_sites #=> [@site]
@site.primary\u文章[@site]
Rails的内置多态性是不是用来影响站点及其各种内容之间的连接的错误机制?它似乎很有用,因为我需要以多对多的方式将多个不同的模型连接到一个公共模型,但我很难找到任何以这种方式使用它的示例

也许复杂性的一部分是我需要在两个方向上的关联——即查看给定文章关联的所有站点,并查看与给定站点关联的所有文章。我听说过这个插件,看起来它可以解决我的问题。但我尝试在这里使用Rails3,但不确定它是否受支持

非常感谢您的任何帮助——即使它只是让我更加清楚地了解了我对多态性在这种情况下的使用的不完善的理解


提前谢谢

只是一个镜头,但是你有没有研究过多态的has\u many:through=>关系?有一些有用的博客文章是关于-尝试和(还有一个问题)。希望这能对你有所帮助,祝你好运

在这种情况下,我不认为多态性是正确的选择,至少从我对系统设计的理解来看是这样。下面是一个使用STI的示例。这很复杂,如果我遗漏了什么,请原谅。我对新的arel语法也不是很在行,所以不能保证它不经过修改就可以正常工作

class Article < ActiveRecord::Base
  has_many :article_associations, :dependent => :destroy
  has_many :sites, :through => :article_associations

  scope :originating_site, lambda { joins(:article_associations).where('content_associations.originating_site' => true).first }
  scope :primary_sites, lambda { joins(:article_associations).where('content_associations.primary_eligable' => true) }
  scope :secondary_sites, lambda { joins(:article_associations).where('content_associations.secondary_eligable' => true) }
end

class Site < ActiveRecord::Base
  has_many :content_associations, :dependent => :destroy
  has_many :article_associations
  has_many :articles, :through => :article_associations
end

class ContentAssociation < ActiveRecord::Base
  belongs_to :site
  belongs_to :primary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :secondary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :originating_site, :class_name => "Site", :foreign_key => "site_id"
end

class ArticleAssociation < ContentAssociation
  belongs_to :article
end
类文章:销毁
有很多:站点,:通过=>:article\u关联
作用域:原始站点,lambda{joins(:article\u associations)。其中('content\u associations.origing\u site'=>true)。first}
范围:主站点,lambda{joins(:article\u associations)。其中('content\u associations.primary\u eligable'=>true)}
作用域:次要站点,lambda{joins(:article\u associations)。其中('content\u associations.secondary\u eligable'=>true)}
结束
类站点:销毁
有很多:文章协会
有很多:文章,:到=>:文章
结束
类ContentAssociation“站点”;外部密钥=>“站点id”
属于:次要站点,:类名称=>“站点”,:外部密钥=>“站点id”
属于:原始站点,:类名称=>“站点”,:外部密钥=>“站点id”
结束
类ArticleAssociation
我在这里做的是为每种数据类型创建一个基本关联模型和一个单独的子关联。因此,如果您需要按类型访问关联,您将可以访问
site.articles
,但您也可以将
site.content\u association
的列表与所有内容放在一起


STI功能需要一个
type:string
列来存储数据类型。除非您使用的是
ContentAssociation
模型,否则这将自动处理。由于
ArticleAssociation
正在使用
article\u id
,您还需要添加它,以及子模型使用的每一列。

如果您需要关联比STI允许的更具扩展性,您可以尝试编写自己的集合帮助程序来执行额外的类型内省

任何时候定义与
所属的关系时,
有多个
有一个
等。您还可以定义与该集合相关的帮助函数:

class Article < ActiveRecord::Base
  has_many :associations, :as => :associable, :dependent => :destroy
  has_many :sites, :through => :article_associations

  scope :originating_site, lambda { joins(:article_associations).where('content_associations.originating_site' => true).first }
  scope :primary_sites, lambda { joins(:article_associations).where('content_associations.primary_eligable' => true) }
  scope :secondary_sites, lambda { joins(:article_associations).where('content_associations.secondary_eligable' => true) }
end

class Site < ActiveRecord::Base
  has_many :content_associations, :as => :associable, :dependent => :destroy do
    def articles
      collect(&:associable).collect { |a| a.is_a? Article }
    end
  end
end

class ContentAssociation < ActiveRecord::Base
  belongs_to :site
  belongs_to :associable, :polymorphic => true
  belongs_to :primary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :secondary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :originating_site, :class_name => "Site", :foreign_key => "site_id"
end

现在它开始变得更像一个通用插件,而不是特定于应用程序的代码。这很好,因为你可以很容易地重用它。

我已经研究了很多:通过多态性,但我的问题更多的是让关联让我把那些额外的布尔属性放在上面,而不是其他任何东西——这就是问题所在;我正在制作一个“胖”连接模型。主要/次要的事情实际上是每个站点的问题,所以它是连接模型上的东西。这就是问题所在——拥有一个同样是多态的“胖”连接模型。
主要文章
次要文章
原始文章
应该是作用域而不是关联。这种方法看起来非常有用——感谢您将其传递给我们。我明白你所说的通过连接使用作用域的意思了,我为自己还没有想到这一点而自责。我一直希望能够使用包含的模块或“acts_as”为任何新的内容类型创建关联,这些内容类型需要它们来保持内容干燥。如果STI依赖于继承而不是mixin,那么这可以在STI的上下文中实现吗?@trevrosen按照我进行关联的方式,您必须为每个数据类型添加一个新列。因此,如果可扩展性非常重要,那么这可能不会很好地工作。但我认为多态性将使处理Assocation变得困难,因此您可能需要使用自己的助手来进行类型检查。
class Article < ActiveRecord::Base
  has_many :associations, :as => :associable, :dependent => :destroy
  has_many :sites, :through => :article_associations

  scope :originating_site, lambda { joins(:article_associations).where('content_associations.originating_site' => true).first }
  scope :primary_sites, lambda { joins(:article_associations).where('content_associations.primary_eligable' => true) }
  scope :secondary_sites, lambda { joins(:article_associations).where('content_associations.secondary_eligable' => true) }
end

class Site < ActiveRecord::Base
  has_many :content_associations, :as => :associable, :dependent => :destroy do
    def articles
      collect(&:associable).collect { |a| a.is_a? Article }
    end
  end
end

class ContentAssociation < ActiveRecord::Base
  belongs_to :site
  belongs_to :associable, :polymorphic => true
  belongs_to :primary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :secondary_site, :class_name => "Site", :foreign_key => "site_id"
  belongs_to :originating_site, :class_name => "Site", :foreign_key => "site_id"
end
module Content
  class Procs
    cattr_accessor :associations
    @@associations = lambda do
      def articles
        collect(&:associable).collect { |a| a.is_a? Article }
      end

      def events
        collect(&:associable).collect { |e| e.is_a? Event }
      end

      def bios
        collect(&:associable).collect { |b| b.is_a? Bio }
      end
    end
  end
end


class Site < ActiveRecord::Base
  has_many :content_associations, :as => :associable, :dependent => :destroy, &Content::Procs.associations
end
module Content
  class Procs
    cattr_accessor :associations
    @@associations = lambda do
      %w(articles events bios).each do |type_name|
        type = eval type_name.singularize.classify
        define_method type_name do
          collect(&:associable).collect { |a| a.is_a? type }
        end
      end
    end
  end
end