Skip to content

Instantly share code, notes, and snippets.

@joekhoobyar
Last active August 29, 2015 13:55
Show Gist options
  • Save joekhoobyar/8699750 to your computer and use it in GitHub Desktop.
Save joekhoobyar/8699750 to your computer and use it in GitHub Desktop.
ActiveRecord query extension: where_exists(related,*where_params)
module ActiveRecord
module FinderMethods
# This simple class acts as a "stand-in" for your association, enabling us to reuse logic
# in ::ActiveRecord::Associations::AssociationScope.
class ExistingAssociation < Struct.new(:klass, :owner, :reflection)
delegate :interpolate, to: :klass
def initialize klass, related
raise ArgumentError if Hash===related && related.length > 1
related, subjoins = Array(related).flatten
reflection = klass.reflect_on_association(related)
super reflection.klass, klass.arel_table, reflection
end
def scope
::ActiveRecord::Associations::AssociationScope.new(self).scope
end
end
# Build a WHERE clause that checks the existance of a related association or relation.
# Any (optional) following arguments will be treated as separate invocations of where(*arg),
# with the additional convenience that a Symbol on the right-hand side will be treated as column
# from this model's table.
def where_exists(related, *where_params)
relation =
case related
when ActiveRecord::Relation then related
else ExistingAssociation.new(@klass, related).scope
end
relation = relation.send(:construct_relation_for_association_find,
relation.send(:construct_join_dependency_for_association_find)).
except(:select, :order).
select("1 AS one")
where("EXISTS (#{where_params.inject relation do |subq,where_param|
if not Hash===where_param then subq.where(where_param) else
subq.where(Hash[ where_param.map do |k,v|
[k, Symbol===v ? @klass.arel_table[v] : v]
end ])
end
end.to_sql})")
end
end
module Querying
delegate :where_exists, to: :scoped
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment