如何使用ActiveRecord将STI表中的不同类合并到单个结果集中?
我们正在构建一个应用程序,创建类似于Facebook的群页面的群页面。有人可以发布到某个页面,该页面可以有回复。因为它们具有非常相似的属性,所以帖子和回复被合并到同一个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 <
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)