Skip to content

Instantly share code, notes, and snippets.

@tlowrimore
Last active January 13, 2023 21:12
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save tlowrimore/5162327 to your computer and use it in GitHub Desktop.
Save tlowrimore/5162327 to your computer and use it in GitHub Desktop.
Unions multiple scopes on a model, and returns an instance of ActiveRecord::Relation.
module ActiveRecord::UnionScope
def self.included(base)
base.send :extend, ClassMethods
end
module ClassMethods
def union_scope(*scopes)
id_column = "#{table_name}.#{primary_key}"
sub_query = scopes.map { |s| s.select(id_column).to_sql }.join(" UNION ")
where "#{id_column} IN (#{sub_query})"
end
end
end
@tlowrimore
Copy link
Author

I guess I should mention that this is a somewhat naive implementation; however, it solves my needs more than 80% of the time.

@mezis
Copy link

mezis commented Jun 22, 2013

Naive but effective. Thanks !

@jfrux
Copy link

jfrux commented Mar 14, 2014

Example usage for beginners?

@batizhevsky
Copy link

I found this solution in SO: http://stackoverflow.com/a/15413611/406438

@araslanov-e
Copy link

"#{table_name}.id" => "#{table_name}.#{primary_key}"

@sekrett
Copy link

sekrett commented Jul 15, 2015

Or like this with Concern

module UnionScope
  extend ActiveSupport::Concern

  class_methods do
    def union_scope(*scopes)
      id_column = "#{table_name}.#{primary_key}"
      sub_query = scopes.map { |s| s.select(id_column).to_sql }.join(' UNION ')
      where "#{id_column} IN (#{sub_query})"
    end
  end
end

@tlowrimore
Copy link
Author

@araslanov-e Thanks for the feedback. I've updated the gist to include your edit.

@tlowrimore
Copy link
Author

Hi everyone, it's been a while!

I've added another GIST that extends the functionality provided in union_scope.rb, to also provide INTERSECT and EXCEPT operations. Inspired by @sekrett, I've structured this one as a Concern.

https://gist.github.com/tlowrimore/f0e3eca483395de3d373

Cheers!
Tim

@ceskmcfran
Copy link

ceskmcfran commented Aug 1, 2017

id_column = "#{table_name}.#{primary_key}"
sub_query = scopes.map { |s| s.select(id_column).to_sql }.join(" UNION ")
where "#{id_column} IN (#{sub_query})"

  1. Is this secure against XSS or SQLi?
  2. I'm new with ruby on rails. Can you use
    where('? IN (?)', id_column, sub_query)
    instead of
    where "#{id_column} IN (#{sub_query})

Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment