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/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 diff --git a/spec/extensions/resources_spec.rb b/spec/extensions/resources_spec.rb index 383bc45..cc66ac5 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? + 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? + 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? + 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? + 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