docbrown/app/validators/profile_validator.rb
Jacob Herrington 45e45491b1
Migrate "static" profile fields into new columns (#13641)
* Move static profile fields to profiles columns

In order to remove some ambiguity around the availability of certain
profile fields, we can designate certain fields as "static." These
fields are intended to exist on every Forem regardless of configuration;
they contain basic personal info that most Forem's will likely use.

Because these fields already exist on some Forems it is necessary to
migrate the data from existing profile's data column to their respective
columns.

This change should behave as expected irrespective of the existence of
the static fields having associated ProfileFields, however, the UI that
is rendered in a user's settings still depends on the presence of the
ProfileFields. We can address that in a future change when we are
prepared to delete those ProfileFields entirely. We should make sure the
migration occurs without issue before moving to that step, in my
opinion.

* Apply suggestions from code review

Co-authored-by: Michael Kohl <me@citizen428.net>

* Add clarifying comments

Co-authored-by: Michael Kohl <me@citizen428.net>

Co-authored-by: Michael Kohl <me@citizen428.net>
2021-05-26 14:40:18 -05:00

71 lines
2.4 KiB
Ruby

class ProfileValidator < ActiveModel::Validator
SUMMARY_ATTRIBUTE = "summary".freeze
MAX_SUMMARY_LENGTH = 200
MAX_TEXT_AREA_LENGTH = 200
MAX_TEXT_FIELD_LENGTH = 100
HEX_COLOR_REGEXP = /^#?(?:\h{6}|\h{3})$/.freeze
ERRORS = {
color_field: "is not a valid hex color",
text_area: "is too long (maximum: #{MAX_TEXT_AREA_LENGTH})",
text_field: "is too long (maximum: #{MAX_TEXT_FIELD_LENGTH})"
}.with_indifferent_access.freeze
def validate(record)
# NOTE: @citizen428 The summary is a base profile field, which we add to all
# new Forem instances, so it should be safe to validate. The method itself
# also guards against the field's absence.
record.errors.add(:summary, "is too long") if summary_too_long?(record)
ProfileField.all.each do |field|
attribute = field.attribute_name
next if attribute == SUMMARY_ATTRIBUTE # validated above
next unless record.respond_to?(attribute) # avoid caching issues
next if __send__("#{field.input_type}_valid?", record, attribute)
record.errors.add(attribute, ERRORS[field.input_type])
end
end
private
def summary_too_long?(record)
# Calling the summary attribute method on record during onboarding
# throws a NoMethodError
return unless record.respond_to?(SUMMARY_ATTRIBUTE)
# TODO: [@jacobherrington] This will need to be addressed when the summary
# ProfileField is dropped from production.
return unless ProfileField.exists?(attribute_name: SUMMARY_ATTRIBUTE)
return if record.summary.blank?
# Grandfather in people who had a too long summary before
# TODO: [@jacobherrington] `record.data_was` can be removed when we delete
# the old data and drop the fields from `Profile.static_fields`.
previous_summary = record.summary_was || record.data_was[SUMMARY_ATTRIBUTE]
return if previous_summary && previous_summary.size > MAX_SUMMARY_LENGTH
record.summary.size > MAX_SUMMARY_LENGTH
end
def check_box_valid?(_record, _attribute)
true # checkboxes are always valid
end
def color_field_valid?(record, attribute)
hex_value = record.public_send(attribute)
hex_value.nil? || hex_value.match?(HEX_COLOR_REGEXP)
end
def text_area_valid?(record, attribute)
text = record.public_send(attribute)
text.nil? || text.size <= MAX_TEXT_AREA_LENGTH
end
def text_field_valid?(record, attribute)
text = record.public_send(attribute)
text.nil? || text.size <= MAX_TEXT_FIELD_LENGTH
end
end