Skip to content

Commit c2ee5fa

Browse files
fix: preserve false values in model fields (#811)
1 parent 2d0acb6 commit c2ee5fa

2 files changed

Lines changed: 57 additions & 6 deletions

File tree

‎lib/auth0/internal/types/model.rb‎

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,22 @@ def initialize(values = {})
141141
values = Utils.symbolize_keys(values.dup)
142142

143143
self.class.fields.each do |field_name, field|
144-
value = values.delete(field.api_name.to_sym) || values.delete(field.api_name) || values.delete(field_name)
144+
# key?/nil? checks keep an explicit `false`, and both keys are consumed so neither leaks into extra fields
145+
value = nil
146+
[field.api_name.to_sym, field_name].uniq.each do |key|
147+
next unless values.key?(key)
145148

146-
field_value = value || (if field.literal?
147-
field.value
148-
elsif field.default
149-
field.default
150-
end)
149+
candidate = values.delete(key)
150+
value = candidate if value.nil?
151+
end
152+
153+
field_value = if !value.nil?
154+
value
155+
elsif field.literal?
156+
field.value
157+
elsif !field.default.nil?
158+
field.default
159+
end
151160

152161
@data[field_name] = Utils.coerce(field.type, field_value)
153162
end

‎test/unit/internal/types/test_model.rb‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ class ExampleWithDefaults < ExampleModel
2424
field :type, String, default: "example"
2525
end
2626

27+
class ExampleWithBooleans < Auth0::Internal::Types::Model
28+
field :blocked, Auth0::Internal::Types::Boolean, optional: true
29+
field :active, Auth0::Internal::Types::Boolean, optional: true, api_name: "isActive"
30+
field :enabled, Auth0::Internal::Types::Boolean, optional: true, default: false
31+
end
32+
2733
class ExampleChild < Auth0::Internal::Types::Model
2834
field :value, String
2935
end
@@ -110,6 +116,42 @@ class ExampleParent < Auth0::Internal::Types::Model
110116
assert_equal 2014, example.year
111117
refute_respond_to example, :yearOfRelease
112118
end
119+
120+
it "preserves false values on construction and in to_h" do
121+
example = ExampleWithBooleans.new(blocked: false, active: false)
122+
123+
assert_same false, example.blocked
124+
assert_same false, example.active
125+
assert_same false, example.to_h["blocked"]
126+
assert_same false, example.to_h["isActive"]
127+
end
128+
129+
it "preserves false values when loaded from JSON" do
130+
example = ExampleWithBooleans.load('{"blocked":false,"isActive":false}')
131+
132+
assert_same false, example.blocked
133+
assert_same false, example.active
134+
end
135+
136+
it "keeps an explicit false instead of falling back to the default" do
137+
assert_same false, ExampleWithBooleans.new.enabled
138+
assert_same true, ExampleWithBooleans.new(enabled: true).enabled
139+
assert_same false, ExampleWithBooleans.new(enabled: false).enabled
140+
end
141+
142+
it "falls back to the field name when the api_name value is nil" do
143+
example = ExampleWithBooleans.new(isActive: nil, active: true)
144+
145+
assert_same true, example.active
146+
refute_respond_to example, :isActive
147+
end
148+
149+
it "does not leak a consumed key into extra fields" do
150+
example = ExampleWithBooleans.new(isActive: false, active: true)
151+
152+
assert_same false, example.active
153+
refute ExampleWithBooleans.extra_fields.key?(:active)
154+
end
113155
end
114156

115157
describe "#inspect" do

0 commit comments

Comments
 (0)