Skip to content

Instantly share code, notes, and snippets.

@shartep
Forked from mesozoic/unscoped_associations.rb
Last active November 10, 2016 01:25
Show Gist options
  • Save shartep/67d0a9d4255e902334bd7eaf94c44d91 to your computer and use it in GitHub Desktop.
Save shartep/67d0a9d4255e902334bd7eaf94c44d91 to your computer and use it in GitHub Desktop.
Module which provides the ability to unscope associations
# Provides the ability to unscope associations, this solves problems described in
# http://stackoverflow.com/questions/1540645/how-to-disable-default-scope-for-a-belongs-to/11012633#11012633
#
# Examples
#
# class Document < ActiveRecord::Base
# default_scope where(deleted: false)
# end
#
# class Comment < ActiveRecord::Base
# extend Unscoped
#
# belongs_to :document
# unscope :document
# end
#
module UnscopedAssociations
# Public: Ensure a previously defined association is not scoped by a default_scope.
#
# associations - The Symbol with the name(s) of the associations to unscope.
#
# Examples
#
# # Unscope a single association
# unscope :document
#
# # Unscope multiple in one way.
# unscope :document, :comments
#
# Raises ArgumentError if the named association does not exist on the model, so ensure
# the association is defined _before_ calling `unscope`.
#
# Returns nothing.
def unscope(*associations)
associations.flatten.each do |association|
unless self.reflect_on_association(*association)
raise ArgumentError, "no association named #{association} exists on this model"
end
class_eval <<-RUBY, __FILE__, __LINE__ + 1
if self.reflect_on_association(#{association.inspect}).options[:polymorphic]
# for polymorphic association the klass is not known for association reflection
def #{association}(force_reload = false)
self.association(#{association.inspect}).klass.unscoped { super(force_reload) }
end
else
def #{association}(force_reload = false)
self.class.reflect_on_association(#{association.inspect}).klass.unscoped { super(force_reload) }
end
end
RUBY
end
end
# Public: Define an association of the given type and ensure it is not scoped by default_scope.
def unscoped_association(association_method, association, *args)
send(association_method, association, *args)
unscope(association)
end
# Public: Define a belongs_to association that ignores the target class's default_scope.
def belongs_to_unscoped(*args)
unscoped_association(:belongs_to, *args)
end
# Public: Define a has_one association that ignores the target class's default_scope.
def has_one_unscoped(*args)
unscoped_association(:has_one, *args)
end
# Public: Define a has_many association that ignores the target class's default_scope.
def has_many_unscoped(*args)
unscoped_association(:has_many, *args)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment