Module: Studio::UserProfile
- Extended by:
- ActiveSupport::Concern
- Defined in:
- app/models/concerns/studio/user_profile.rb
Overview
The four things every Studio app's User has had to define for itself: how to name a person on screen, and how to draw them when they have no picture.
WHY THIS EXISTS. The engine's own components/_avatar partial calls
display_name, avatar_initials and avatar_color — and the engine has
never provided any of them. Every consumer wrote its own; mcritchie-industries'
user.rb even carries a comment explaining that it must, because the engine's
nav renders the partial. Three copies, and by 2026-08-14 they had drifted:
mcritchie-studio name → email prefix (capitalized) → wallet → "anon"
mcritchie-industries name → email prefix (raw) → "User"
turf-monster username → name → email prefix (cap) → wallet → "anon"
Same intent, three answers, and two different words for the same empty state. That is the drift a concern removes.
ON THE MERGED CHAIN. It is turf-monster's — the richest of the three — with
first_name folded in after name, because /profile now lets people set that
field and a name someone just typed should be the name they see. Apps missing
a link in the chain simply skip it; the chain is respond_to?-guarded end to
end, so mcritchie-industries' eight-column users table walks it without
raising. One consequence worth stating rather than burying: an MI user with no
name now falls back to "anon" instead of "User", and an email-derived name is
capitalized. That is MI adopting the house standard, and its adoption task
owns the change.
EVERY METHOD IS OVERRIDABLE. These are plain instance methods from an included
module, so a host that defines its own display_name in the class body wins
outright. Standardizing the default is the goal; forbidding an app from having
an opinion is not.
Constant Summary collapse
- AVATAR_COLORS =
The house palette for initial-circle backgrounds. Identical in all three apps today, which is the clearest possible signal it belonged here.
%w[#EF4444 #F97316 #EAB308 #22C55E #06B6D4 #3B82F6 #8B5CF6 #EC4899].freeze
Instance Method Summary collapse
-
#avatar_color ⇒ Object
A stable colour for this account — same person, same circle, every render.
-
#avatar_initials ⇒ Object
One character for the initials circle.
-
#display_name ⇒ Object
What to call this person on screen.
Instance Method Details
#avatar_color ⇒ Object
A stable colour for this account — same person, same circle, every render. Hashed rather than random for exactly that reason, and keyed off identity fields so it survives a display-name change.
71 72 73 74 75 76 77 78 |
# File 'app/models/concerns/studio/user_profile.rb', line 71 def avatar_color key = studio_profile_username.presence || studio_profile_attr(:name).presence || studio_profile_attr(:email).presence || id.to_s AVATAR_COLORS[Digest::MD5.hexdigest(key.to_s).hex % AVATAR_COLORS.size] end |
#avatar_initials ⇒ Object
One character for the initials circle. Deliberately NOT derived from display_name: that chain ends in a wallet address or the word "anon", and "a" for every anonymous account is worse than a neutral mark.
56 57 58 59 60 61 62 63 64 65 66 |
# File 'app/models/concerns/studio/user_profile.rb', line 56 def avatar_initials source = studio_profile_username.presence || studio_profile_attr(:name).presence || studio_profile_attr(:first_name).presence || studio_profile_email_prefix.presence # `source[0]`, not ActiveSupport's `String#first`: this module is included # into a host model, and nothing here should depend on which core_ext that # host happens to have loaded. Plain Ruby costs nothing and cannot vanish. source.presence.to_s[0]&.upcase || "?" end |
#display_name ⇒ Object
What to call this person on screen.
44 45 46 47 48 49 50 51 |
# File 'app/models/concerns/studio/user_profile.rb', line 44 def display_name studio_profile_username.presence || studio_profile_attr(:name).presence || studio_profile_attr(:first_name).presence || studio_profile_email_prefix.presence || studio_profile_wallet.presence || "anon" end |