acts_as_sourceable 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +25 -0
- data/lib/acts_as_sourceable/acts_as_sourceable.rb +53 -81
- data/lib/acts_as_sourceable/registry_entry.rb +9 -0
- data/lib/acts_as_sourceable.rb +1 -1
- metadata +5 -16
- data/README.rdoc +0 -3
- data/lib/acts_as_sourceable/registry.rb +0 -12
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# ActsAsSourceable
|
2
|
+
|
3
|
+
Allows the RRN to perform garbage project on categories that are no longer referenced.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
### In your gemfile
|
8
|
+
```ruby
|
9
|
+
gem 'acts_as_sourceable'
|
10
|
+
```
|
11
|
+
|
12
|
+
### Migration
|
13
|
+
```ruby
|
14
|
+
create_table :acts_as_sourceable_registry do |t|
|
15
|
+
t.belongs_to :sourceable, :polymorphic => true
|
16
|
+
t.belongs_to :source, :polymorphic => true
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :acts_as_sourceable_registry, [:sourceable_id, :sourceable_type], :name => :index_acts_as_sourceable_sourceables
|
21
|
+
add_index :acts_as_sourceable_registry, [:source_id, :source_type], :name => :index_acts_as_sourceable_sources
|
22
|
+
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
@@ -15,8 +15,8 @@ module ActsAsSourceable
|
|
15
15
|
if acts_as_sourceable_options[:through]
|
16
16
|
def sources; send(acts_as_sourceable_options[:through]) || []; end
|
17
17
|
else
|
18
|
-
|
19
|
-
def sources;
|
18
|
+
has_many :sourceable_registry_entries, :class_name => 'ActsAsSourceable::RegistryEntry', :as => :sourceable, :dependent => :delete_all
|
19
|
+
def sources; self.sourceable_registry_entries.includes(:source).collect(&:source); end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -25,7 +25,7 @@ module ActsAsSourceable
|
|
25
25
|
|
26
26
|
# If a cache column is provided, use that to determine which records are sourced and unsourced
|
27
27
|
# Elsif the records can be derived, we need to check the flattened item tables for any references
|
28
|
-
# Else we check the
|
28
|
+
# Else we check the registry_entries to see if the record has a recorded source
|
29
29
|
if options[:cache_column]
|
30
30
|
scope :sourced, where(options[:cache_column] => true)
|
31
31
|
scope :unsourced, where(options[:cache_column] => false)
|
@@ -33,25 +33,18 @@ module ActsAsSourceable
|
|
33
33
|
scope :sourced, joins(options[:through]).uniq
|
34
34
|
scope :unsourced, joins("LEFT OUTER JOIN (#{sourced.to_sql}) sourced ON sourced.id = #{table_name}.id").where("sourced.id IS NULL")
|
35
35
|
else
|
36
|
-
scope :sourced, joins(:
|
36
|
+
scope :sourced, joins(:sourceable_registry_entries).uniq
|
37
37
|
scope :unsourced, joins("LEFT OUTER JOIN (#{sourced.to_sql}) sourced ON sourced.id = #{table_name}.id").where("sourced.id IS NULL")
|
38
38
|
end
|
39
39
|
|
40
40
|
# Add a way of finding everything sourced by a particular set of records
|
41
41
|
if options[:through]
|
42
|
-
def sourced_by(
|
43
|
-
|
42
|
+
def self.sourced_by(source)
|
43
|
+
self.joins(acts_as_sourceable_options[:through]).where(reflect_on_association(acts_as_sourceable_options[:through]).table_name => {:id => source.id})
|
44
44
|
end
|
45
45
|
else
|
46
|
-
def sourced_by(
|
47
|
-
|
48
|
-
|
49
|
-
arel_table = ActsAsSourceable::Registry.arel_table
|
50
|
-
h_contraint = arel_table[:holding_institution_ids].array_overlap(holding_institution_ids)
|
51
|
-
c_contraint = arel_table[:collection_ids].array_overlap(collection_ids)
|
52
|
-
i_contraint = arel_table[:item_ids].array_overlap(item_ids)
|
53
|
-
|
54
|
-
sourced.where(h_contraint.or(c_contraint).or(i_contraint))
|
46
|
+
def self.sourced_by(source)
|
47
|
+
self.joins(:sourceable_registry_entries).where(ActsAsSourceable::RegistryEntry.table_name => {:source_type => source.class, :source_id => source.id}).uniq
|
55
48
|
end
|
56
49
|
end
|
57
50
|
|
@@ -86,7 +79,7 @@ module ActsAsSourceable
|
|
86
79
|
|
87
80
|
def unsource
|
88
81
|
scoping { @klass.update_all("#{acts_as_sourceable_options[:cache_column]} = false", @klass.acts_as_sourceable_options[:cache_column] => true) } if @klass.acts_as_sourceable_options[:cache_column]
|
89
|
-
scoping { ActsAsSourceable::
|
82
|
+
scoping { ActsAsSourceable::RegistryEntry.where("sourceable_type = ? AND sourceable_id IN (#{@klass.select("#{@klass.table_name}.id").to_sql})", @klass.name).delete_all }
|
90
83
|
end
|
91
84
|
end
|
92
85
|
|
@@ -115,94 +108,73 @@ module ActsAsSourceable
|
|
115
108
|
|
116
109
|
# Add the given holding_institutions, collections, and items
|
117
110
|
def add_sources(*sources)
|
118
|
-
|
119
|
-
|
120
|
-
|
111
|
+
raise "Cannot set sources of a #{self.class.name}. They are sourced through #{acts_as_sourceable_options[:through]}" if acts_as_sourceable_options[:through]
|
112
|
+
|
113
|
+
sources = Array(sources).flatten
|
114
|
+
sources.each do |source|
|
115
|
+
source_scope(source).first_or_create!
|
116
|
+
end
|
117
|
+
update_sourceable_cache_column(true) if sources.present?
|
121
118
|
end
|
122
119
|
alias_method :add_source, :add_sources
|
123
120
|
|
124
121
|
# Remove the given holding_institutions, collections, and items
|
125
122
|
def remove_sources(*sources)
|
126
|
-
|
127
|
-
registry = init_registry_entry
|
128
|
-
set_sources(registry.holding_institution_ids - holding_institution_ids, registry.collection_ids - collection_ids, registry.item_ids - item_ids)
|
129
|
-
end
|
130
|
-
alias_method :remove_source, :remove_sources
|
123
|
+
raise "Cannot set sources of a #{self.class.name}. They are sourced through #{acts_as_sourceable_options[:through]}" if acts_as_sourceable_options[:through]
|
131
124
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
def set_sources(holding_institution_ids, collection_ids, item_ids)
|
136
|
-
registry = init_registry_entry
|
137
|
-
registry.holding_institution_ids = Array(holding_institution_ids).uniq
|
138
|
-
registry.collection_ids = Array(collection_ids).uniq
|
139
|
-
registry.item_ids = Array(item_ids).uniq
|
140
|
-
|
141
|
-
if holding_institution_ids.any? || collection_ids.any? || item_ids.any?
|
142
|
-
registry.save!
|
143
|
-
set_sourceable_cache_column(true)
|
144
|
-
elsif registry.persisted?
|
145
|
-
registry.destroy
|
146
|
-
set_sourceable_cache_column(false)
|
125
|
+
sources = Array(sources).flatten
|
126
|
+
sources.each do |source|
|
127
|
+
source_scope(source).delete_all
|
147
128
|
end
|
129
|
+
update_sourceable_cache_column(false) if self.sourceable_registry_entries.empty?
|
148
130
|
end
|
131
|
+
alias_method :remove_source, :remove_sources
|
149
132
|
|
150
133
|
private
|
151
134
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
ActsAsSourceable::Registry.where(:sourceable_type => self.class.name, :sourceable_id => self.id).first_or_initialize
|
135
|
+
def source_scope(source)
|
136
|
+
ActsAsSourceable::RegistryEntry.where(:sourceable_type => self.class.name, :sourceable_id => self.id, :source_type => source.class, :source_id => source.id)
|
156
137
|
end
|
157
|
-
|
158
|
-
def
|
159
|
-
|
138
|
+
|
139
|
+
def update_sourceable_cache_column(value = nil)
|
140
|
+
return unless acts_as_sourceable_options[:cache_column] # Update via sql because we don't need callbacks and validations called
|
141
|
+
|
142
|
+
if value
|
143
|
+
update_column(acts_as_sourceable_options[:cache_column], value)
|
144
|
+
else
|
145
|
+
update_column(acts_as_sourceable_options[:cache_column], sourceable_registry_entries.present?)
|
146
|
+
end
|
160
147
|
end
|
161
148
|
end
|
162
149
|
|
163
150
|
module HelperMethods
|
164
|
-
#
|
165
|
-
# Order of return arrays is [HoldingInstitutions, Collections, Items]
|
166
|
-
def self.group_by_class(*sources)
|
167
|
-
groups = Array(sources).flatten.group_by(&:class)
|
168
|
-
return [groups[HoldingInstitution] || [], groups[Collection] || [], groups[Item] || []]
|
169
|
-
end
|
170
|
-
|
171
|
-
def self.group_ids_by_class(*sources)
|
172
|
-
group_by_class(*sources).collect!{|group| group.collect(&:id)}
|
173
|
-
end
|
174
|
-
|
175
|
-
# Removes sourceable institutions that no longer belong to a record or holding institution
|
151
|
+
# Removes registry entries that no longer belong to a sourceable, item, collection, or holding institution
|
176
152
|
def self.garbage_collect
|
177
|
-
|
153
|
+
# Remove all registry entries where the sourceable is gone
|
154
|
+
ActsAsSourceable::RegistryEntry.pluck(:sourceable_type).uniq.each do |sourceable_type|
|
178
155
|
sourceable_table_name = sourceable_type.constantize.table_name
|
179
|
-
sourceable_id_sql = ActsAsSourceable::
|
180
|
-
.select("#{ActsAsSourceable::
|
156
|
+
sourceable_id_sql = ActsAsSourceable::RegistryEntry
|
157
|
+
.select("#{ActsAsSourceable::RegistryEntry.table_name}.id")
|
181
158
|
.where(:sourceable_type => sourceable_type)
|
182
|
-
.joins("LEFT OUTER JOIN #{sourceable_table_name} ON #{sourceable_table_name}.id = #{ActsAsSourceable::
|
159
|
+
.joins("LEFT OUTER JOIN #{sourceable_table_name} ON #{sourceable_table_name}.id = #{ActsAsSourceable::RegistryEntry.table_name}.sourceable_id")
|
183
160
|
.where("#{sourceable_table_name}.id IS NULL").to_sql
|
184
161
|
|
185
|
-
ActsAsSourceable::
|
162
|
+
ActsAsSourceable::RegistryEntry.delete_all("id IN (#{sourceable_id_sql})")
|
186
163
|
end
|
187
164
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
registries.includes(:sourceable).each do |registry|
|
202
|
-
item_ids = Item.where(:id => registry.item_ids).pluck(:id)
|
203
|
-
# ActiveRecord::Base.logger.debug "Registry #{registry.id}: holding_institution_ids: #{registry.holding_institution_ids.inspect} => #{registry.holding_institution_ids & holding_institution_ids}, collection_ids: #{registry.collection_ids.inspect} => #{registry.collection_ids & collection_ids}, item_ids: #{registry.item_ids.inspect} => #{registry.item_ids & item_ids} "
|
204
|
-
registry.sourceable.set_sources(registry.holding_institution_ids & holding_institution_ids, registry.collection_ids & collection_ids, registry.item_ids & item_ids)
|
205
|
-
end
|
165
|
+
# Remove all registry entries where the source is gone
|
166
|
+
ActsAsSourceable::RegistryEntry.pluck(:source_type).uniq.each do |source_type|
|
167
|
+
source_class = source_type.constantize
|
168
|
+
source_table_name = source_class.table_name
|
169
|
+
source_id_sql = ActsAsSourceable::RegistryEntry
|
170
|
+
.select("#{ActsAsSourceable::RegistryEntry.table_name}.id")
|
171
|
+
.where(:source_type => source_type)
|
172
|
+
.joins("LEFT OUTER JOIN #{source_table_name} ON #{source_table_name}.id = #{ActsAsSourceable::RegistryEntry.table_name}.source_id")
|
173
|
+
.where("#{source_table_name}.id IS NULL").to_sql
|
174
|
+
|
175
|
+
sourceables = ActsAsSourceable::RegistryEntry.where("id IN (#{source_id_sql})").collect(&:sourceable)
|
176
|
+
ActsAsSourceable::RegistryEntry.where("id IN (#{source_id_sql})").delete_all
|
177
|
+
sourceables.each{|sourceable| sourceable.send(:update_sourceable_cache_column) }
|
206
178
|
end
|
207
179
|
end
|
208
180
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module ActsAsSourceable
|
2
|
+
class RegistryEntry < ActiveRecord::Base
|
3
|
+
self.table_name = 'acts_as_sourceable_registry'
|
4
|
+
|
5
|
+
belongs_to :sourceable, :polymorphic => true
|
6
|
+
belongs_to :source, :polymorphic => true
|
7
|
+
validates_presence_of :sourceable_type, :sourceable_id, :source_type, :source_id
|
8
|
+
end
|
9
|
+
end
|
data/lib/acts_as_sourceable.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_sourceable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,18 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
date: 2013-01-26 00:00:00.000000000 Z
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
16
|
-
name: postgres_ext
|
17
|
-
requirement: &70193900896400 !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
|
-
requirements:
|
20
|
-
- - ~>
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 0.1.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: *70193900896400
|
14
|
+
dependencies: []
|
26
15
|
description: Allows the RRN to perform garbage collection on categories that are no
|
27
16
|
longer referenced.
|
28
17
|
email: technical@rrnpilot.org
|
@@ -31,9 +20,9 @@ extensions: []
|
|
31
20
|
extra_rdoc_files: []
|
32
21
|
files:
|
33
22
|
- lib/acts_as_sourceable/acts_as_sourceable.rb
|
34
|
-
- lib/acts_as_sourceable/
|
23
|
+
- lib/acts_as_sourceable/registry_entry.rb
|
35
24
|
- lib/acts_as_sourceable.rb
|
36
|
-
- README.
|
25
|
+
- README.md
|
37
26
|
homepage: http://github.com/rrn/acts_as_sourceable
|
38
27
|
licenses: []
|
39
28
|
post_install_message:
|
@@ -54,7 +43,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
43
|
version: '0'
|
55
44
|
requirements: []
|
56
45
|
rubyforge_project:
|
57
|
-
rubygems_version: 1.8.
|
46
|
+
rubygems_version: 1.8.25
|
58
47
|
signing_key:
|
59
48
|
specification_version: 3
|
60
49
|
summary: perform garbage collection on categories that are no longer referenced
|
data/README.rdoc
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
module ActsAsSourceable
|
2
|
-
class Registry < ActiveRecord::Base
|
3
|
-
self.table_name = 'acts_as_sourceable_registry'
|
4
|
-
|
5
|
-
belongs_to :sourceable, :polymorphic => true
|
6
|
-
validates_presence_of :sourceable_type, :sourceable_id
|
7
|
-
|
8
|
-
def sources
|
9
|
-
HoldingInstitution.find(self.holding_institution_ids) + Collection.find(self.collection_ids) + Item.find(self.item_ids)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|