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
手に入れたいですpage.posts_and_replies
ページの「最も気に入った投稿または返信」などを見つけるには、投稿と返信を組み合わせて、次のような結果セットを取得する必要があります。
top_messages = page.posts_and_replies.order_by('total_likes DESC').limit(10)
投稿と返信を一緒に出すのは難しい
単一の結果セットとして並べ替えるposts_and_replies
には、通常は単一の結合に基づいてクエリを実行する必要があります。
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)
page_id
にしか存在しないため、これを行うことはできませんposts
。「返信」は、それらが属する投稿を通じてのみページを参照します。したがって、この結合は投稿を提供しますが、返信は提供しません。
可能な解決策:
データを非正規化します...
Reply と Post にを複製することもできpage_id
ますが、非正規化されたデータは涙で終わる傾向があるため、可能であればそれを避けたいと思います。
カスタムを使用するfinder_sql
カスタム finder sql を使用して、投稿と返信を別々に取得し、それらを結合することができます。
class Page < ActiveRecord::Base
has_many :posts
has_many :replies
has_many :posts_and_replies, class_name: 'BasePost', finder_sql: Proc.new{
"select base_posts.* from base_posts
where page_id = #{self.id}
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 = #{self.id}"
}
end
カスタム finder_sql は機能しますが、関連付け拡張では機能しません
上記の finder_sql は実際には機能しますが、関連拡張機能はどれも機能しません。関連拡張機能 ( など.where
) を使用しようとすると、組み込みの finder_sql にフォールバックします。
これは機能します
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
*ただし、これは誤った finder_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_sql
アソシエーション拡張機能が指定された finder_sql を尊重するようにするにはどうすればよいですか?
問題は、finder_sql を適切に使用していない関連付け拡張機能に要約されているようです。これを強制する方法はありますか?