3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/acts_as_sourceable/acts_as_sourceable.rb', line 3
def acts_as_sourceable(options = {})
options.assert_valid_keys :through, :cache_column, :used_by
raise "Can't have a cache column and be sourced through an association" if options[:through] && options [:cache_column]
class_attribute :acts_as_sourceable_options
self.acts_as_sourceable_options = options
include ActsAsSourceable::InstanceMethods
class_eval do
if acts_as_sourceable_options[:through]
def sources; send(acts_as_sourceable_options[:through]) || []; end
else
has_many :sourceable_registry_entries, :class_name => 'ActsAsSourceable::RegistryEntry', :as => :sourceable, :dependent => :delete_all
def sources; self.sourceable_registry_entries.includes(:source).collect(&:source); end
end
end
extend ActsAsSourceable::ClassMethods
if options[:cache_column]
scope :sourced, lambda { where(options[:cache_column] => true) }
scope :unsourced, lambda { where(options[:cache_column] => false) }
elsif options[:through]
scope :sourced, lambda { joins(options[:through]).group("#{table_name}.#{primary_key}") } do include ActsAsSourceable::GroupScopeExtensions; end
scope :unsourced, lambda { joins("LEFT OUTER JOIN (#{sourced.to_sql}) sourced ON sourced.id = #{table_name}.id").where("sourced.id IS NULL") }
else
scope :sourced, lambda { joins(:sourceable_registry_entries).group("#{table_name}.#{primary_key}") } do include ActsAsSourceable::GroupScopeExtensions; end
scope :unsourced, lambda { joins("LEFT OUTER JOIN (#{ActsAsSourceable::RegistryEntry.select('sourceable_id AS id').where(:sourceable_type => self).to_sql}) sourced ON sourced.id = #{table_name}.id").where("sourced.id IS NULL") }
end
if options[:through]
scope :sourced_by, lambda { |source| joins(options[:through]).where(reflect_on_association(options[:through]).table_name => {:id => source.id}) }
else
scope :sourced_by, lambda { |source| joins(:sourceable_registry_entries).where(ActsAsSourceable::RegistryEntry.table_name => {:source_type => source.class, :source_id => source.id}).uniq }
end
if options[:used_by]
scope :unused, lambda { where(Array(options[:used_by]).collect {|usage_association| "#{table_name}.id NOT IN (" + select("#{table_name}.id").joins(usage_association).group("#{table_name}.id").to_sql + ")"}.join(' AND ')) }
scope :orphaned, lambda { unsourced.unused }
else
scope :orphaned, lambda { unsourced }
end
ActiveRecord::Relation.send(:include, ActsAsSourceable::ActiveRelationMethods)
class << self
delegate :add_sources, :add_source, :remove_source, :remove_sources, :unsource, :to => :scoped
end
end
|