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
|
# 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 { from(unscoped.joins(options[:through]).group("#{table_name}.#{primary_key}"), table_name) }
scope :unsourced, lambda { readonly(false).joins("LEFT OUTER JOIN (#{sourced.to_sql}) sourced ON sourced.id = #{table_name}.id").where("sourced.id IS NULL") }
else
scope :sourced, lambda { from(unscoped.joins(:sourceable_registry_entries).group("#{table_name}.#{primary_key}"), table_name) }
scope :unsourced, lambda { readonly(false).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| readonly(false).joins(options[:through]).where(reflect_on_association(options[:through]).table_name => {:id => source.id}) }
else
scope :sourced_by, lambda { |source| readonly(false).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 :used, lambda { where(Array(options[:used_by]).collect {|usage_association| "#{table_name}.id IN (" + select("#{table_name}.id").joins(usage_association).group("#{table_name}.id").to_sql + ")"}.join(' OR ')) }
scope :orphaned, lambda { unsourced.unused }
else
scope :orphaned, lambda { unsourced }
end
end
|