Add 'apps/arv-web/' from commit 'f9732ad8460d013c2f28363655d0d1b91894dca5'
[arvados.git] / services / api / lib / can_be_an_owner.rb
1 # Protect referential integrity of owner_uuid columns in other tables
2 # that can refer to the uuid column in this table.
3
4 module CanBeAnOwner
5
6   def self.included(base)
7     # Rails' "has_many" can prevent us from destroying the owner
8     # record when other objects refer to it.
9     ActiveRecord::Base.connection.tables.each do |t|
10       next if t == base.table_name
11       next if t == 'schema_migrations'
12       klass = t.classify.constantize
13       next unless klass and 'owner_uuid'.in?(klass.columns.collect(&:name))
14       base.has_many(t.to_sym,
15                     foreign_key: :owner_uuid,
16                     primary_key: :uuid,
17                     dependent: :restrict)
18     end
19     # We need custom protection for changing an owner's primary
20     # key. (Apart from this restriction, admins are allowed to change
21     # UUIDs.)
22     base.validate :restrict_uuid_change_breaking_associations
23   end
24
25   protected
26
27   def restrict_uuid_change_breaking_associations
28     return true if new_record? or not uuid_changed?
29
30     # Check for objects that have my old uuid listed as their owner.
31     self.class.reflect_on_all_associations(:has_many).each do |assoc|
32       next unless assoc.foreign_key == :owner_uuid
33       if assoc.klass.where(owner_uuid: uuid_was).any?
34         errors.add(:uuid,
35                    "cannot be changed on a #{self.class} that owns objects")
36         return false
37       end
38     end
39
40     # if I owned myself before, I'll just continue to own myself with
41     # my new uuid.
42     if owner_uuid == uuid_was
43       self.owner_uuid = uuid
44     end
45   end
46
47 end