after_create :log_create
after_update :log_update
after_destroy :log_destroy
+ after_find :convert_serialized_symbols_to_strings
validate :ensure_serialized_attribute_type
validate :normalize_collection_uuids
validate :ensure_valid_uuids
# Note: This only returns permission links. It does not account for
# permissions obtained via user.is_admin or
# user.uuid==object.owner_uuid.
- has_many :permissions, :foreign_key => :head_uuid, :class_name => 'Link', :primary_key => :uuid, :conditions => "link_class = 'permission'", dependent: :destroy
+ has_many :permissions, :foreign_key => :head_uuid, :class_name => 'Link', :primary_key => :uuid, :conditions => "link_class = 'permission'"
class PermissionDeniedError < StandardError
def http_status
def ensure_owner_uuid_is_permitted
raise PermissionDeniedError if !current_user
- self.owner_uuid ||= current_user.uuid
+ if respond_to? :owner_uuid=
+ self.owner_uuid ||= current_user.uuid
+ end
if self.owner_uuid_changed?
- if current_user.uuid == self.owner_uuid or
+ if new_record?
+ return true
+ elsif current_user.uuid == self.owner_uuid or
current_user.can? write: self.owner_uuid
# current_user is, or has :write permission on, the new owner
else
true
end
+ def self.has_symbols? x
+ if x.is_a? Hash
+ x.each do |k,v|
+ return true if has_symbols?(k) or has_symbols?(v)
+ end
+ false
+ elsif x.is_a? Array
+ x.each do |k|
+ return true if has_symbols?(k)
+ end
+ false
+ else
+ (x.class == Symbol)
+ end
+ end
+
+ def self.recursive_stringify x
+ if x.is_a? Hash
+ Hash[x.collect do |k,v|
+ [recursive_stringify(k), recursive_stringify(v)]
+ end]
+ elsif x.is_a? Array
+ x.collect do |k|
+ recursive_stringify k
+ end
+ elsif x.is_a? Symbol
+ x.to_s
+ else
+ x
+ end
+ end
+
def ensure_serialized_attribute_type
# Specifying a type in the "serialize" declaration causes rails to
# raise an exception if a different data type is retrieved from
# developer.
self.class.serialized_attributes.each do |colname, attr|
if attr.object_class
- unless self.attributes[colname].is_a? attr.object_class
- self.errors.add colname.to_sym, "must be a #{attr.object_class.to_s}"
+ if self.attributes[colname].class != attr.object_class
+ self.errors.add colname.to_sym, "must be a #{attr.object_class.to_s}, not a #{self.attributes[colname].class.to_s}"
+ elsif self.class.has_symbols? attributes[colname]
+ self.errors.add colname.to_sym, "must not contain symbols: #{attributes[colname].inspect}"
end
end
end
end
+ def convert_serialized_symbols_to_strings
+ # ensure_serialized_attribute_type should prevent symbols from
+ # getting into the database in the first place. If someone managed
+ # to get them into the database (perhaps using an older version)
+ # we'll convert symbols to strings when loading from the
+ # database. (Otherwise, loading and saving an object with existing
+ # symbols in a serialized field will crash.)
+ self.class.serialized_attributes.each do |colname, attr|
+ if self.class.has_symbols? attributes[colname]
+ attributes[colname] = self.class.recursive_stringify attributes[colname]
+ self.send(colname + '=',
+ self.class.recursive_stringify(attributes[colname]))
+ end
+ end
+ end
+
def foreign_key_attributes
attributes.keys.select { |a| a.match /_uuid$/ }
end