X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/c7ee5e02cae78d3edff6ed393d776c4995441896..35c20b4ad8220131f7f6bad6b3806a7d28df3ef3:/services/api/app/models/arvados_model.rb diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb index a6c9d31d41..95fd055d49 100644 --- a/services/api/app/models/arvados_model.rb +++ b/services/api/app/models/arvados_model.rb @@ -20,6 +20,7 @@ class ArvadosModel < ActiveRecord::Base 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 @@ -263,6 +264,38 @@ class ArvadosModel < ActiveRecord::Base 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 @@ -272,13 +305,31 @@ class ArvadosModel < ActiveRecord::Base # 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