Skip to content

Instantly share code, notes, and snippets.

@tahb
Created March 13, 2020 17:45
Show Gist options
  • Save tahb/79f2457c0f05fe07c47841e2eda694a4 to your computer and use it in GitHub Desktop.
Save tahb/79f2457c0f05fe07c47841e2eda694a4 to your computer and use it in GitHub Desktop.
WIP extending govuk form builder so radio inputs support checked defaults
Rails.application.config.action_view.default_form_builder = GOVUKDesignSystemFormBuilder::FormBuilder
# Don't use XHR when submitting forms
Rails.application.config.action_view.form_with_generates_remote_forms = false
# Use activerecord.attributes.model.attribute_name for label scope
module GOVUKDesignSystemFormBuilder
module Builder
def govuk_collection_radio_buttons(attribute_name, collection, value_method, text_method, hint_method = nil, hint_text: nil, legend: {}, inline: false, small: false, bold_labels: false, checked: false, classes: nil, &block)
Elements::Radios::Collection.new(
self,
object_name,
attribute_name,
collection,
value_method: value_method,
text_method: text_method,
hint_method: hint_method,
hint_text: hint_text,
legend: legend,
inline: inline,
small: small,
bold_labels: bold_labels,
classes: classes,
checked: checked,
&block
).html
end
end
class Base
private def localised_text(context)
key = localisation_key(context)
return nil unless I18n.exists?(key)
translation = I18n.translate(key)
translation = translation.fetch(:html).html_safe if translation.is_a?(Hash) && translation.key?(:html)
translation
end
private def localisation_key(context)
return nil unless @object_name.present? && @attribute_name.present?
if context == "label"
["activerecord", "attributes", @object_name, @attribute_name].join(".")
else
["helpers", context, @object_name, @attribute_name].join(".")
end
end
def has_errors?
@builder.object.errors.any? &&
@builder.object.errors.messages.dig(
translated_attribute_name(attribute_name: @attribute_name)
).present?
end
# In order to support associations where the model association is
# eg. `provider` but the form attribute needs to be `provider_id`.
# The form field must be wrapped in errors and be linkable from the summary.
#
# 1. We cannot change the form field to `provider` since the value will
# not read from an object with a value already set.
#
# 2. We cannot change the model association to be `provider_id` as calling
# `transaction.provider_id` rather than the resource `transaction.provider`
# would be unconventional and also require a hack.
#
# 3. We cannot overwride the @attribute_name on create since that will have
# the same affect as point 1.
private def translated_attribute_name(attribute_name:)
translations = @builder.object.class.try("::FORM_FIELD_TRANSLATIONS") || {}
if translations[attribute_name].present?
translations[attribute_name]
else
attribute_name
end
end
end
end
module GOVUKDesignSystemFormBuilder
module Elements
class Select < GOVUKDesignSystemFormBuilder::Base
def error_element
@error_element ||= Elements::ErrorMessage.new(
@builder,
@object_name,
translated_attribute_name(attribute_name: @attribute_name)
)
end
def field_id(link_errors: false)
if link_errors && has_errors?
build_id(
"field-error",
include_value: false,
attribute_name: translated_attribute_name(attribute_name: @attribute_name)
)
else
build_id("field")
end
end
end
module Radios
def initialize(builder, object_name, attribute_name, collection, value_method:, text_method:, hint_method:, hint_text:, legend:, inline:, small:, bold_labels:, checked: false, classes:, &block)
super(builder, object_name, attribute_name, &block)
@collection = collection
@value_method = value_method
@text_method = text_method
@hint_method = hint_method
@inline = inline
@small = small
@legend = legend
@hint_text = hint_text
@classes = classes
@bold_labels = hint_method.present? || bold_labels
@checked = checked
end
class CollectionRadioButton < GOVUKDesignSystemFormBuilder::Base
def initialize(builder, object_name, attribute_name, item, value_method:, text_method:, hint_method:, link_errors: false, bold_labels:, checked: false)
super(builder, object_name, attribute_name)
@item = item
@value = retrieve(item, value_method)
@label_text = retrieve(item, text_method)
@hint_text = retrieve(item, hint_method)
@link_errors = link_errors
@bold_labels = bold_labels
@checked = checked
end
def retrieve(item, method)
case method
when Symbol, String
item.send(method)
when Proc
method.call(item)
end
end
def html
content_tag('div', class: 'govuk-radios__item') do
safe_join(
[
@builder.radio_button(
@attribute_name,
@value,
id: field_id(link_errors: @link_errors),
aria: { describedby: hint_id },
class: %w(govuk-radios__input),
checked: @checked,
),
label_element.html,
hint_element.html
]
)
end
end
def field_id(link_errors: false)
if link_errors && has_errors?
build_id(
"field-error",
include_value: false,
attribute_name: translated_attribute_name(attribute_name: @attribute_name)
)
else
build_id("field")
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment