docbrown/app/models/profile.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

75 lines
2.2 KiB
Ruby

class Profile < ApplicationRecord
belongs_to :user
validates :data, presence: true
validates :user_id, uniqueness: true
validates_with ProfileValidator
has_many :custom_profile_fields, dependent: :destroy
store_attribute :data, :custom_attributes, :json, default: {}
# Static fields are columns on the profiles table; they have no relationship
# to a ProfileField record. These are columns we can safely assume exist for
# any profile on a given Forem.
STATIC_FIELDS = %w[summary location website_url].freeze
SPECIAL_DISPLAY_ATTRIBUTES = %w[
summary
employment_title
employer_name
employer_url
location
].freeze
# NOTE: @citizen428 This is a temporary mapping so we don't break DEV during
# profile migration/generalization work.
MAPPED_ATTRIBUTES = {
brand_color1: :bg_color_hex,
brand_color2: :text_color_hex,
display_email_on_profile: :email_public,
education: :education,
skills_languages: :mostly_work_with
}.with_indifferent_access.freeze
# Generates typed accessors for all currently defined profile fields.
def self.refresh_attributes!
return if ENV["ENV_AVAILABLE"] == "false"
return unless Database.table_available?("profiles")
ProfileField.find_each do |field|
# Don't generate accessors for static fields stored on the table.
# TODO: [@jacobherrington] Remove this when ProfileFields for the static
# fields are dropped from production and the associated data is removed.
# https://github.com/forem/forem/pull/13641#discussion_r637641185
next if STATIC_FIELDS.any?(field.attribute_name)
store_attribute :data, field.attribute_name.to_sym, field.type
end
end
# Set up all profile attributes when this class loads so all store_attribute
# accessors get defined immediately.
refresh_attributes!
# Returns an array of all currently defined `store_attribute`s on `data`.
def self.attributes
(stored_attributes[:data] || []).map(&:to_s)
end
def self.special_attributes
SPECIAL_DISPLAY_ATTRIBUTES
end
def self.static_fields
STATIC_FIELDS
end
def custom_profile_attributes
custom_profile_fields.pluck(:attribute_name)
end
def clear!
update(data: {})
end
end