diff --git a/lib/active_model/entity/schemas/json.rb b/lib/active_model/entity/schemas/json.rb index b4af63e..81e1cb0 100644 --- a/lib/active_model/entity/schemas/json.rb +++ b/lib/active_model/entity/schemas/json.rb @@ -82,8 +82,9 @@ def append_description_if_available!(name, options) options[:description] = meta_descriptions[key] if meta_descriptions.key?(key) end - def append_enum!(values, options) - options[:enum] = values + def append_enum!(values, options, type) + target = type.is_a?(Type::Array) ? options[:items] : options + target[:enum] = values end def as_json_schema(inline: false) @@ -99,7 +100,7 @@ def as_json_schema(inline: false) properties.each do |name, options| make_schema_nullable!(options) if nullable.key?(name) append_description_if_available!(name, options) - append_enum!(enums[name], options) if enums.key?(name) + append_enum!(enums[name], options, attributes[name]) if enums.key?(name) end { type:, description:, required:, properties: }.compact diff --git a/spec/active_model/entity/schemas/json_spec.rb b/spec/active_model/entity/schemas/json_spec.rb index f9a8121..1a00c67 100644 --- a/spec/active_model/entity/schemas/json_spec.rb +++ b/spec/active_model/entity/schemas/json_spec.rb @@ -29,6 +29,7 @@ class Person attribute :field_nullable_not_required_string, :string attribute :field_enum_string, :string attribute :field_enum_int, :integer + attribute :field_enum_string_array, :array, of: :string validates :field_boolean, presence: true validates :field_float, presence: true @@ -38,6 +39,7 @@ class Person validates :field_nullable_not_required_role, presence: { allow_nil: true, required: false } validates :field_enum_string, inclusion: { in: %w[an enum] } validates :field_enum_int, inclusion: { in: [1, 3, 7] } + validates :field_enum_string_array, inclusion: { in: %w[an enum] } end end @@ -62,7 +64,8 @@ class Person "fieldNullableNotRequiredString" => { type: :string, nullable: true }, "fieldWithoutType" => { type: :object }, "fieldEnumString" => { type: :string, enum: %w[an enum] }, - "fieldEnumInt" => { type: :number, enum: [1, 3, 7] } } + "fieldEnumInt" => { type: :number, enum: [1, 3, 7] }, + "fieldEnumStringArray" => { type: :array, items: { type: :string, enum: %w[an enum] } } } expect(schema).to eq({ type: :object, @@ -122,5 +125,36 @@ class Person items: { type: :number } }) end + + it "keeps enum on items for array of enums" do + schema = SchemasTest::Person.as_json_schema(inline: true) + + expect(schema[:properties]["fieldEnumStringArray"]).to eq({ + type: :array, + items: { type: :string, enum: %w[an enum] } + }) + end + end + + describe "validation of arrays of enums" do + let(:entity) { SchemasTest::Person.new(field_boolean: true, field_float: 1.0, field_nullable_string: "x") } + + it "is valid when all elements are in the allowed set" do + entity.field_enum_string_array = %w[an enum] + entity.valid? + expect(entity.errors[:field_enum_string_array]).to be_empty + end + + it "is invalid when any element is not in the allowed set" do + entity.field_enum_string_array = %w[an other] + entity.valid? + expect(entity.errors[:field_enum_string_array]).not_to be_empty + end + + it "is valid when the array is empty" do + entity.field_enum_string_array = [] + entity.valid? + expect(entity.errors[:field_enum_string_array]).to be_empty + end end end