如何使用ActiveRecord将STI表中的不同类合并到单个结果集中?

如何使用ActiveRecord将STI表中的不同类合并到单个结果集中?,activerecord,ruby-on-rails-3.2,sti,finder-sql,Activerecord,Ruby On Rails 3.2,Sti,Finder Sql,我们正在构建一个应用程序,创建类似于Facebook的群页面的群页面。有人可以发布到某个页面,该页面可以有回复。因为它们具有非常相似的属性,所以帖子和回复被合并到同一个STI表中 class Page < ActiveRecord::Base has_many :posts has_many :replies, through: :posts end class BasePost < ActiveRecord::Base ... end class Post <

我们正在构建一个应用程序,创建类似于Facebook的群页面的群页面。有人可以发布到某个页面,该页面可以有回复。因为它们具有非常相似的属性,所以帖子和回复被合并到同一个STI表中

class Page < ActiveRecord::Base
  has_many :posts
  has_many :replies, through: :posts
end

class BasePost < ActiveRecord::Base
  ...
end

class Post < BasePost
  belongs_to :page
  ...
end

class Reply < BasePost
  belongs_to :post
  ...
end
把帖子和回复放在一起很难 要将帖子和回复作为单个结果集进行排序,尽管我们通常需要基于单个连接进行查询:

class Page < ActiveRecord::Base
  has_many :posts
  has_many :replies, through: :posts
  has_many :posts_and_replies, class_name: 'BasePost'
end

# ideally we could then do queries such as
most_recent_messages = @page.posts_and_replies.order('created_at DESC').limit(10)
自定义finder_sql可以工作,但不能与关联扩展一起工作 上面的finder_sql实际上可以工作,但是关联扩展都不能工作。每当我尝试使用关联扩展(如
。where
)时,它都会返回到内置的finder\u sql:

这很有效

*但是,这要归咎于错误的查找程序\u sql*

  Page.find(8).posts_and_replies.where('total_likes > 1')
  => select "base_posts".* from "base_posts" where "base_posts"."page_id" = 8 
     and (total_likes > 12)
由于某些原因,关联扩展没有使用正确的
finder\u sql

如何使关联扩展尊重声明的finder\u sql?
问题似乎归结为关联扩展没有正确使用finder_sql。有什么方法可以强制执行吗?

最简单的方法可能是使用一些命名的作用域,并完全避免关联。这是一种稍微有点不规范的方式,但可能会给你你想要的——我不确定Rails协会是否真的会给你你想要的行为。另外,请注意,下面我将使用ActiveRecord的安全参数插值-您应该永远不要自己将字符串插值到SQL语句中-当您不查看时,它会召唤恶魔来侵入您的数据库

首先,您将在BasePost模型中定义一个命名范围,该范围执行以下操作:

class BasePost < ActiveRecord::Base

  scope :popular_posts_for_page, lambda { |page_id|
    where("base_posts.page_id = ? OR parent_posts.page_id = ?", page_id, page_id).
     joins("left outer join base_posts parent_posts on parent_posts.id = base_posts.post_id").
     order("total_likes DESC")
  }

end
应该完全按照你的期望去做


对于SQL中的任何错误,我深表歉意。

我感到困惑。您说页面有很多:回复,但回复不属于:页面,这是应该如何设置的。你的意思是像Page has\u many:repress,:through=>:posts这样的东西吗?@rob,你是对的(就我所记得的而言),我刚刚更新了这个问题以反映它包含了
has\u many through:
关系-ty
 Page.find(8).posts_and_replies
 => select base_posts.* from base_posts 
      where page_id = 8
    UNION
      select 
      base_posts.*
      from base_posts left join base_posts as head_posts
      on base_posts.post_id = head_posts.id
      where head_posts.page_id = 8
  Page.find(8).posts_and_replies.where('total_likes > 1')
  => select "base_posts".* from "base_posts" where "base_posts"."page_id" = 8 
     and (total_likes > 12)
class BasePost < ActiveRecord::Base

  scope :popular_posts_for_page, lambda { |page_id|
    where("base_posts.page_id = ? OR parent_posts.page_id = ?", page_id, page_id).
     joins("left outer join base_posts parent_posts on parent_posts.id = base_posts.post_id").
     order("total_likes DESC")
  }

end
class Page < ActiveRecord::Base

  def popular_posts_and_replies
    BasePost.popular_posts_for_page(self.id)
  end

end
my_page.popular_posts_and_replies.limit(10)