14873: Custom JSON attributes that default to [] or {} when nil.
authorLucas Di Pentima <ldipentima@veritasgenetics.com>
Tue, 2 Apr 2019 21:36:08 +0000 (18:36 -0300)
committerLucas Di Pentima <ldipentima@veritasgenetics.com>
Tue, 2 Apr 2019 21:36:08 +0000 (18:36 -0300)
Previously we used the 'serialize' call to declare a JSONB column as a Hash
or Array and this had the side effect to default to an empty hash or array
when assigning nil (whether was reading from the database or passed as a param).
JSONB columns shouldn't be now declared as serialized because Rails would serialize
their contents twice, but not declaring them makes us lose their side effect.

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima@veritasgenetics.com>

services/api/app/models/collection.rb
services/api/app/models/container.rb
services/api/app/models/container_request.rb
services/api/app/models/group.rb
services/api/app/models/jsonb_type.rb [new file with mode: 0644]
services/api/app/models/link.rb
services/api/app/models/node.rb
services/api/config/initializers/custom_types.rb [new file with mode: 0644]

index cb23df1c219ef4404a2023e824303bf54d7922ff..e6d8d8655202a2c081d3a696ca4d9a409a027be6 100644 (file)
@@ -16,8 +16,10 @@ class Collection < ArvadosModel
 
   # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
   # already know how to properly treat them.
+  attribute :properties, :jsonbHash, default: {}
+  attribute :storage_classes_desired, :jsonbArray, default: ["default"]
+  attribute :storage_classes_confirmed, :jsonbArray, default: []
 
-  before_validation :fill_field_defaults
   before_validation :default_empty_manifest
   before_validation :default_storage_classes, on: :create
   before_validation :check_encoding
@@ -653,10 +655,4 @@ class Collection < ArvadosModel
     self.current_version_uuid ||= self.uuid
     true
   end
-
-  def fill_field_defaults
-    self.properties ||= {}
-    self.storage_classes_desired ||= []
-    self.storage_classes_confirmed ||= []
-  end
 end
index b02989457e8c632765833fc5767842b72836638d..fb900a993d464e809fd93ce0ecdacdae35995027 100644 (file)
@@ -19,6 +19,10 @@ class Container < ArvadosModel
 
   # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
   # already know how to properly treat them.
+  attribute :secret_mounts, :jsonbHash, default: {}
+  attribute :runtime_status, :jsonbHash, default: {}
+  attribute :runtime_auth_scopes, :jsonbHash, default: {}
+
   serialize :environment, Hash
   serialize :mounts, Hash
   serialize :runtime_constraints, Hash
index 80e1bf3ffe5c7c84bf2251f88b8aa5cb9628404e..292decafbfb94ad381ab84bcfe01da13c5e9d68d 100644 (file)
@@ -21,6 +21,9 @@ class ContainerRequest < ArvadosModel
 
   # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
   # already know how to properly treat them.
+  attribute :properties, :jsonbHash, default: {}
+  attribute :secret_mounts, :jsonbHash, default: {}
+
   serialize :environment, Hash
   serialize :mounts, Hash
   serialize :runtime_constraints, Hash
index b63d0ae2af0b67da2ec3f957fd55f61b8307a795..7fb8fef42ba9e4c1b19967174cd30c9991383726 100644 (file)
@@ -14,6 +14,7 @@ class Group < ArvadosModel
 
   # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
   # already know how to properly treat them.
+  attribute :properties, :jsonbHash, default: {}
 
   after_create :invalidate_permissions_cache
   after_update :maybe_invalidate_permissions_cache
@@ -50,5 +51,4 @@ class Group < ArvadosModel
     end
     true
   end
-
 end
diff --git a/services/api/app/models/jsonb_type.rb b/services/api/app/models/jsonb_type.rb
new file mode 100644 (file)
index 0000000..2011dce
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+class JsonbType
+  # Emulate pre-rails5.0 behavior by having a interpreting NULL/nil as
+  # some other default value.
+  class WithDefault < ActiveModel::Type::Value
+    include ActiveModel::Type::Helpers::Mutable
+    @@default_value = nil
+
+    def deserialize(value)
+      if value.nil?
+        @@default_value
+      elsif value.is_a?(::String)
+        SafeJSON.load(value) rescue @@default_value
+      else
+        value
+      end
+    end
+
+    def serialize(value)
+      if value.nil?
+        @@default_value
+      else
+        SafeJSON.dump(value)
+      end
+    end
+  end
+
+  class Hash < JsonbType::WithDefault
+    @@default_value = {}
+  end
+
+  class Array < JsonbType::WithDefault
+    @@default_value = []
+  end
+end
\ No newline at end of file
index a95feb83cdaf4cb6362ee7c7ab5a4e70cad43d49..ad7800fe679cb91936bde76f00566873cb369419 100644 (file)
@@ -9,6 +9,7 @@ class Link < ArvadosModel
 
   # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
   # already know how to properly treat them.
+  attribute :properties, :jsonbHash, default: {}
 
   before_create :permission_to_attach_to_objects
   before_update :permission_to_attach_to_objects
@@ -101,5 +102,4 @@ class Link < ArvadosModel
       super
     end
   end
-
 end
index ecafcdd218db171d1209bc4ebdebb549ce17329d..148dffc23074138af0d70008e2cc49dd8b344ca1 100644 (file)
@@ -11,8 +11,9 @@ class Node < ArvadosModel
 
   # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
   # already know how to properly treat them.
+  attribute :properties, :jsonbHash, default: {}
+  attribute :info, :jsonbHash, default: {}
 
-  before_validation :fill_field_defaults
   before_validation :ensure_ping_secret
   after_update :dns_server_update
 
@@ -141,11 +142,6 @@ class Node < ArvadosModel
 
   protected
 
-  def fill_field_defaults
-    self.info ||= {}
-    self.properties ||= {}
-  end
-
   def assign_hostname
     if self.hostname.nil? and Rails.configuration.assign_node_hostname
       self.hostname = self.class.hostname_for_slot(self.slot_number)
diff --git a/services/api/config/initializers/custom_types.rb b/services/api/config/initializers/custom_types.rb
new file mode 100644 (file)
index 0000000..aecd4cf
--- /dev/null
@@ -0,0 +1,8 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+# JSONB backed Hash & Array types that default to their empty versions when
+# reading NULL from the database, or get nil passed by parameter.
+ActiveRecord::Type.register(:jsonbHash, JsonbType::Hash)
+ActiveRecord::Type.register(:jsonbArray, JsonbType::Array)