Skip to content

Commit

Permalink
Prepare the HTML attribute hash for Rails 6.0.3
Browse files Browse the repository at this point in the history
Rails 6.0.3 doesn't appear to like receiving HTML attribute lists (like
classes) as arrays. This has been improved from Rails 6.1.0 but to
maintain backward-compatibility we're joining the arrays.

This is taken care of by the Attributes class.

Refs #256
  • Loading branch information
peteryates committed Apr 12, 2021
1 parent 61fd216 commit fa22de2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def options
{
id: field_id(link_errors: @link_errors),
class: %(#{brand}-checkboxes__input),
aria: { describedby: [hint_id] }
aria: { describedby: hint_id }
}
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def radio
def options
{
id: field_id(link_errors: @link_errors),
aria: { describedby: [hint_id] },
aria: { describedby: hint_id },
class: %(#{brand}-radios__input)
}
end
Expand Down
55 changes: 30 additions & 25 deletions lib/govuk_design_system_formbuilder/traits/html_attributes.rb
Original file line number Diff line number Diff line change
@@ -1,45 +1,50 @@
module GOVUKDesignSystemFormBuilder
module Traits
module HTMLAttributes
class Parser
# target any element where the content is a string that represents a
# list of things separated by a space, e.g.,
#
# <span class="red spots">xyz</span>
#
# could be respresented as
#
# = span(class: %w(red spots)) { "xyz" }
TARGETS = [%i(class), %i(aria describedby)].freeze

def initialize(attributes)
@attributes = parse(attributes)
# Attributes eases working with default and custom attributes by
# * deeply merging them so both the default (required) attributes are
# present
# * joins the arrays into strings to maintain Rails 6.0.3 compatibility
class Attributes
def initialize(defaults, custom)
@merged = defaults.deeper_merge(deep_split_values(custom))
end

def to_h
@attributes
deep_join_values(@merged)
end

private

def parse(attributes)
attributes.tap do |a|
a[:class] = a[:class].split if has_class_string?(a)
a[:aria][:describedby] = a[:aria][:describedby].split if has_aria_describedby_string?(attributes)
def deep_split_values(hash)
hash.each.with_object({}) do |(key, value), result|
result[key] = case value
when Hash
deep_split_values(value)
when String
value.split
else
value
end
end
end

def has_class_string?(attributes)
attributes.key?(:class) && attributes[:class].is_a?(String)
end

def has_aria_describedby_string?(attributes)
attributes.dig(:aria, :describedby)&.is_a?(String)
def deep_join_values(hash)
hash.each.with_object({}) do |(key, value), result|
result[key] = case value
when Hash
deep_join_values(value)
when Array
value.uniq.join(' ').presence
else
value
end
end
end
end

def attributes(html_attributes = {})
options.deeper_merge(Parser.new(html_attributes).to_h)
Attributes.new(options, html_attributes).to_h
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
end
end

specify 'radio buttons without hints shouldn not have aria-describedby attributes' do
specify 'radio buttons without hints should not have aria-describedby attributes' do
colours_without_descriptions.each do |cwd|
"person-favourite_colour-#{cwd.id}-hint".tap do |association|
expect(subject).not_to have_tag('input', with: { "aria-describedby" => association })
Expand Down

0 comments on commit fa22de2

Please sign in to comment.