我一直在绞尽脑汁试图想出这个问题,所以我认为是时候在这里发表了。
我有一个类称为Flair
-它是多态的,因为很多东西可以有Flair:
class Flair < ActiveRecord::Base
belongs_to :flairable, polymorphic: true, touch: true
belongs_to :user
end
一个Comment
有多个Flairs
:
class Comment < ActiveRecord::Base
has_many :flairs, as: :flairable
end
当获得评论列表时,我还想知道哪些评论具有属于给定用户的Flair。
到目前为止我能想到的最好的是
# don't worry about the interpolation; just for the example
# and assume we have valid @comments and user_id
@comments.select('comments.*').
select('flairs.id as has_flaired').
joins("left join flairs on flairable_id = comments.id and flairs.user_id = #{user_id}")
但是这将为Comment上的每个Flair返回一个结果(正如左连接所期望的那样),有效地将数组中每个Comment的出现次数乘以其拥有的Flair数量。
我试过使用distinct on (user_id)
,应用limit
等,但这些努力只会出现语法错误。
谁能提供一些指导?特别有用的是一个指向文档中某个地方的指针,那里有比这里提供的例子更复杂的例子:http://www.postgresql.org/docs/9.4/static/sql-select.html。我也尝试了http://www.postgresql.org/docs/9.4/static/queries-table-expressions.html上的建议,但似乎没有什么能坚持下去。
谢谢!
www.postgresql.org/docs/9.4/static/queries-table-expressions.html中的7.2.1.3节和这里的第一个例子,以及一个非常耐心的老板最终帮助解决了这个问题。最后(在敲击键盘一段时间之后),我终于设法用语法正确的查询来取悦Postgres/ActiveRecord神(我们在将user_id
传递给joins
语句之前对其进行了消毒)。
@comments.select(
"comments.*,
flairs.id as has_flaired"
).joins(
"left join
flairs on flairs.id = (
select id from flairs where flairs.user_id = #{user_id}
and flairs.flairable_id = comments.id
limit 1
)"
)
这是有效的,因为我只感兴趣的行与该用户和flairable_id是否存在于flairs表,所以我们只是检查表在子查询和使用主查询的结果。
现在我已经写出来了,但我将把它留在这里,以防其他人同样感到困惑。