From add16c8bde3eaabdf29687f6c71d94029b18e2f7 Mon Sep 17 00:00:00 2001 From: TSMMark Date: Tue, 26 Aug 2025 16:15:45 -0400 Subject: [PATCH 1/3] support resource that is not a list --- .vscode/settings.json | 5 ++ lib/gourami/extensions/resources.rb | 24 ++++-- spec/extensions/resources_spec.rb | 117 ++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 7 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..012b037 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "uids" + ] +} diff --git a/lib/gourami/extensions/resources.rb b/lib/gourami/extensions/resources.rb index cf706e9..eaac4e0 100644 --- a/lib/gourami/extensions/resources.rb +++ b/lib/gourami/extensions/resources.rb @@ -72,7 +72,7 @@ def with_each_resource(resource_namespace, offset: nil, &_block) # validate_presence(:trim_end_time) # validates `attributes[:social_broadcasts]["facebook_page-41"][:trim_end_time]` # end # end - def with_resource(resource_namespace, resource_uid, offset: nil, &_block) + def with_resource(resource_namespace, resource_uid = nil, offset: nil, &_block) @resource_namespace = resource_namespace @resource_uid = resource_uid @offset = offset @@ -86,8 +86,10 @@ def with_resource(resource_namespace, resource_uid, offset: nil, &_block) # If a resource namespace is active (within with_resource block), find the resource using the namespace and uid. # Otherwise, return the form object. def current_resource - if @resource_namespace + if @resource_namespace && @resource_uid send(@resource_namespace)[@resource_uid] + elsif @resource_namespace + send(@resource_namespace) else super end @@ -156,13 +158,21 @@ def resource_errors end # TODO: YARD - def resource_has_errors?(resource_namespace, resource_uid) - resource_errors[resource_namespace][resource_uid.to_s].values.map(&:flatten).any? + def resource_has_errors?(resource_namespace, resource_uid = nil) + resource_errors[resource_namespace][resource_uid&.to_s].values.map(&:flatten).any? end # TODO: YARD - def resource_attribute_has_errors?(resource_namespace, resource_uid, attribute_name) - resource_errors[resource_namespace][resource_uid.to_s][attribute_name].any? + def resource_attribute_has_errors?(resource_namespace, resource_uid_or_attribute_name, attribute_name = nil) + if attribute_name.nil? + # 2 arguments: resource_namespace, attribute_name + attribute_name = resource_uid_or_attribute_name + resource_uid = nil + else + # 3 arguments: resource_namespace, resource_uid, attribute_name + resource_uid = resource_uid_or_attribute_name + end + resource_errors[resource_namespace][resource_uid&.to_s][attribute_name].any? end # Append an error to the given attribute for a resource. @@ -174,7 +184,7 @@ def resource_attribute_has_errors?(resource_namespace, resource_uid, attribute_n # @param error [Symbol, String] # The error identifier. def append_resource_error(resource_namespace, resource_uid, attribute_name, error) - resource_errors[resource_namespace][resource_uid.to_s][attribute_name] << error + resource_errors[resource_namespace][resource_uid&.to_s][attribute_name] << error end # Determine if current form instance is valid by running the validations diff --git a/spec/extensions/resources_spec.rb b/spec/extensions/resources_spec.rb index 383bc45..d71b745 100644 --- a/spec/extensions/resources_spec.rb +++ b/spec/extensions/resources_spec.rb @@ -56,6 +56,12 @@ end, }, ) + form.attribute( + :item, + description: "One object that is a Hash (not a list)", + type: :hash, + key_type: :string, + ) end end @@ -107,6 +113,15 @@ end end + assert_equal({ + items: { + (offset + 2).to_s => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + }, + }, form.resource_errors) + assert_equal(false, form.resource_has_errors?(:items, offset + 0)) assert_equal(false, form.resource_has_errors?(:items, offset + 1)) assert_equal(true, form.resource_has_errors?(:items, offset + 2)) @@ -118,6 +133,19 @@ assert_equal(false, form.resource_attribute_has_errors?(:items, offset + 1, :id)) assert_equal(true, form.resource_attribute_has_errors?(:items, offset + 2, :name)) assert_equal(true, form.resource_attribute_has_errors?(:items, offset + 2, :id)) + + # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. + # TODO: Should we try to update the library to avoid that that? + assert_equal({ + items: { + (offset + 2).to_s => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + (offset + 0).to_s => { name: [], id: [] }, + (offset + 1).to_s => { name: [], id: [] } + }, + }, form.resource_errors) end end @@ -188,6 +216,15 @@ received_indexes ) + assert_equal({ + items: { + (offset + 2).to_s => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + }, + }, form.resource_errors) + assert_equal(false, form.resource_has_errors?(:items, offset + 0)) assert_equal(false, form.resource_has_errors?(:items, offset + 1)) assert_equal(true, form.resource_has_errors?(:items, offset + 2)) @@ -199,6 +236,19 @@ assert_equal(false, form.resource_attribute_has_errors?(:items, offset + 1, :id)) assert_equal(true, form.resource_attribute_has_errors?(:items, offset + 2, :name)) assert_equal(true, form.resource_attribute_has_errors?(:items, offset + 2, :id)) + + # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. + # TODO: Should we try to update the library to avoid that that? + assert_equal({ + items: { + (offset + 2).to_s => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + (offset + 0).to_s => { name: [], id: [] }, + (offset + 1).to_s => { name: [], id: [] } + }, + }, form.resource_errors) end end @@ -227,6 +277,15 @@ end end + assert_equal({ + items_hash: { + "ghi" => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + }, + }, form.resource_errors) + assert_equal(false, form.resource_has_errors?(:items_hash, "abc")) assert_equal(false, form.resource_has_errors?(:items_hash, "def")) assert_equal(true, form.resource_has_errors?(:items_hash, "ghi")) @@ -238,6 +297,18 @@ assert_equal(false, form.resource_attribute_has_errors?(:items_hash, "def", :id)) assert_equal(true, form.resource_attribute_has_errors?(:items_hash, "ghi", :name)) assert_equal(true, form.resource_attribute_has_errors?(:items_hash, "ghi", :id)) + + # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. + # TODO: Should we try to update the library to avoid that that? + assert_equal({ + items_hash: { + "ghi" => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + "abc" => { name: [], id: [] }, "def" => { name: [], id: [] } + }, + }, form.resource_errors) end end @@ -307,6 +378,15 @@ received_indexes ) + assert_equal({ + items_hash: { + "ghi" => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + }, + }, form.resource_errors) + assert_equal(false, form.resource_has_errors?(:items_hash, "abc")) assert_equal(false, form.resource_has_errors?(:items_hash, "def")) assert_equal(true, form.resource_has_errors?(:items_hash, "ghi")) @@ -318,6 +398,43 @@ assert_equal(false, form.resource_attribute_has_errors?(:items_hash, "def", :id)) assert_equal(true, form.resource_attribute_has_errors?(:items_hash, "ghi", :name)) assert_equal(true, form.resource_attribute_has_errors?(:items_hash, "ghi", :id)) + + # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. + # TODO: Should we try to update the library to avoid that that? + assert_equal({ + items_hash: { + "ghi" => { + name: [:cant_be_empty], + id: [:is_invalid], + }, + "abc" => { name: [], id: [] }, "def" => { name: [], id: [] } + }, + }, form.resource_errors) + end + end + + describe "#with_resource(:item) # Hash/Input Object" do + it "validations within the block are scoped to the resource" do + form = form_class.new( + item: { + name: "", + id: 789, + }, + ) + + assert_equal(false, form.resource_has_errors?(:item)) + assert_equal(false, form.resource_attribute_has_errors?(:item, :name)) + assert_equal(false, form.resource_attribute_has_errors?(:item, :id)) + + form.with_resource(:item) do + form.validate_presence(:name) + form.append_error(:id, :is_invalid) if form.item["id"] > 500 + end + + assert_equal(true, form.resource_has_errors?(:item)) + assert_equal(true, form.resource_attribute_has_errors?(:item, :name)) + assert_equal(true, form.resource_attribute_has_errors?(:item, :id)) + assert_equal({ item: { nil => { name: [:cant_be_empty], id: [:is_invalid] } } }, form.resource_errors) end end end From 1ab05452a893dfdf02950255a82de3ac300c060b Mon Sep 17 00:00:00 2001 From: TSMMark Date: Tue, 26 Aug 2025 17:11:39 -0400 Subject: [PATCH 2/3] @MVV90 review typo --- spec/extensions/resources_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/extensions/resources_spec.rb b/spec/extensions/resources_spec.rb index d71b745..cc66ac5 100644 --- a/spec/extensions/resources_spec.rb +++ b/spec/extensions/resources_spec.rb @@ -135,7 +135,7 @@ assert_equal(true, form.resource_attribute_has_errors?(:items, offset + 2, :id)) # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. - # TODO: Should we try to update the library to avoid that that? + # TODO: Should we try to update the library to avoid that? assert_equal({ items: { (offset + 2).to_s => { @@ -238,7 +238,7 @@ assert_equal(true, form.resource_attribute_has_errors?(:items, offset + 2, :id)) # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. - # TODO: Should we try to update the library to avoid that that? + # TODO: Should we try to update the library to avoid that? assert_equal({ items: { (offset + 2).to_s => { @@ -299,7 +299,7 @@ assert_equal(true, form.resource_attribute_has_errors?(:items_hash, "ghi", :id)) # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. - # TODO: Should we try to update the library to avoid that that? + # TODO: Should we try to update the library to avoid that? assert_equal({ items_hash: { "ghi" => { @@ -400,7 +400,7 @@ assert_equal(true, form.resource_attribute_has_errors?(:items_hash, "ghi", :id)) # Checking resource_attribute_has_errors? applies a default empty array to the errors hash. - # TODO: Should we try to update the library to avoid that that? + # TODO: Should we try to update the library to avoid that? assert_equal({ items_hash: { "ghi" => { From bc7d159ef6ca768857cb200dadb5bdedd0cd9dce Mon Sep 17 00:00:00 2001 From: TSMMark Date: Tue, 26 Aug 2025 17:12:12 -0400 Subject: [PATCH 3/3] 2.1.0 --- lib/gourami/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gourami/version.rb b/lib/gourami/version.rb index c7b6afa..b0b202d 100644 --- a/lib/gourami/version.rb +++ b/lib/gourami/version.rb @@ -1,3 +1,3 @@ module Gourami - VERSION = "2.0.0".freeze + VERSION = "2.1.0".freeze end