← Back to people
AL

Ada Lovelace

ada@example.com
★ Admin Moderator

Wrote the first algorithm. Fond of analytical engines.


Roles — presence via add / remove

Contact — two Address slots, two Phone slots

Basket Orders

The same Address component declared twice, prefix: :shipping and prefix: :billing, and Phone as mobile and work — one row per slot in the shared tables, and none at all until a field is filled.

Shipping address

Located at -31.94916, 115.86342 (simulated) · Geocoder

Billing address

Located at -31.95135, 115.85640 (simulated) · Geocoder

How this works

Make moderator is user.add(:moderator): one row in markers under slot moderator. Remove moderator deletes it. A marker has no columns of its own, because whether the row exists is the whole answer.

Save contact details writes only the slots that hold a value. Both addresses live in the addresses table, which also holds the sellers' addresses and the orders' copies. The slot is what tells them apart.

The declaration · app/entities/user.rb

component Name                     # user.name_given, user.name_family, user.name.initials
component Email                    # user.email_address, user.email_verified
component Image, prefix: :avatar   # user.avatar_image.url
component Text,  prefix: :bio      # user.bio (the String), user.bio_text (the Text)
component Address, prefix: :shipping    # user.shipping_address
component Address, prefix: :billing     # user.billing_address
component Geolocation, prefix: :shipping # user.shipping_geolocation
component Geolocation, prefix: :billing  # user.billing_geolocation
component Phone,   prefix: :mobile      # user.mobile_phone
component Phone,   prefix: :work        # user.work_phone
marker :moderator
marker :administrator
has_many :posts,       via: :author   # user.posts
has_many :comments,    via: :author   # user.comments
has_many :memberships, via: :user     # user.memberships
has_many :employments, via: :user     # user.employments — the seller side, same user
has_many :reviews,     via: :author   # user.reviews
has_one  :basket,      via: :customer # user.basket — the child's unique: true makes this a has_one
has_many :orders,      via: :customer # user.orders

The rows behind it

WhereRow
entities
  • id = 7b37fc34…
  • model = users
names default slot
  • family = Lovelace
  • given = Ada
emails default slot
  • address = ada@example.com
  • verified = false
images slot avatar No row: avatar_image reads its column defaults
texts slot bio
  • value = Wrote the first algorithm. Fond of anal…
addresses slot shipping
  • country = AU
  • line1 = 12 Ada Lovelace Ln
  • locality = Perth
  • postcode = 6000
  • region = WA
addresses slot billing
  • country = AU
  • line1 = PO Box 1815
  • locality = Perth
  • postcode = 6001
  • region = WA
geolocations slot shipping
  • geocoded_at = 2026-11-05 04:00:00 UTC
  • lat = -31.9491605
  • lng = 115.8634159
geolocations slot billing
  • geocoded_at = 2026-11-05 04:00:00 UTC
  • lat = -31.9513514
  • lng = 115.8563971
phones slot mobile
  • e164 = +61412345678
phones slot work No row: work_phone reads its column defaults
markers slot moderator A row, with no other columns
markers slot administrator A row, with no other columns

Every slot row also has id, entity_id (this entity's id) and timestamps. Ids are cut to their first block. The rows are the ones this page loaded, so the panel adds no queries.

Posts by Ada · 1