やりたいこと
ActiveRecordでunion使いたい
どうやるか
調べてもよくわからなかったので、下記を追加した
config/initializer/model_customizer.rb
ActiveRecord::Base.send(:define_singleton_method , "union", proc { |*queries|
from "(#{ queries.map { |q| q.ast.to_sql }.join(' UNION ') }) AS #{self.table_name}"
})
つかいかた
app/model/post.rb
self.union(query1, query2, query3)
注意
scopeでorder定義しているときはunscopeしないとSQLExceptionになる。
unionメソッド定義の中でunscopedするとsqlが変わってしまうので、渡す前にunscopedすることにした。
例:
app/model/post.rb
default_scope -> { order('created_at DESC') }
def self.from_users_followed_by(user)
followed_user_ids = "SELECT followed_id FROM relationships WHERE follower_id = :user_id"
where("user_id IN (#{followed_user_ids}) OR user_id = :user_id", user_id: user.id)
end
def self.from_tags_followed_by(user)
subquery1 = "SELECT tag_id FROM tag_follows WHERE user_id = :user_id"
subquery2 = "SELECT post_id FROM taggings WHERE tag_id IN (#{subquery1})"
where("id IN (#{subquery2}) ", user_id: user.id)
end
def self.feed(user)
self.union(
self.unscoped.from_users_followed_by(user),
self.unscoped.from_tags_followed_by(user)
).order('created_at DESC')
end