Skip to content

Conversation

@giallon
Copy link
Collaborator

@giallon giallon commented Feb 3, 2026

Add Polymorphic Support for Embedded Associations

Overview

Adds polymorphic embedded associations to embeds_one and embeds_many, allowing different document types to be embedded in the same association.

Features Added

1. Polymorphic Embedded Associations

  • embeds_one: Embed different types in a single association
  • embeds_many: Embed collections of mixed types
  • Type information stored inside each embedded document as a type field

2. Hash Input with Type Key

Accept hashes with type key for convenient polymorphic initialization:

post = Post.new(media: { type: 'image', url: 'photo.jpg', caption: 'Sunset' })
  • Uses snake_case class names ('image'Image)
  • Supports both symbol and string keys
  • Raises ArgumentError if type key missing

3. Type Restrictions

Restrict allowed types by passing array to polymorphic:

class Post < CouchbaseOrm::Base
  embeds_one :media, polymorphic: ['Image', 'Video']
end
  • polymorphic: false - Not polymorphic (default)
  • polymorphic: true - Polymorphic, any type allowed
  • polymorphic: ['Image', 'Video'] - Only specified types allowed
  • Auto-converts snake_case to CamelCase ([:image, 'video']['Image', 'Video'])

Examples

embeds_one

class Image < CouchbaseOrm::Base
  attribute :url, :string
  attribute :caption, :string
end

class Video < CouchbaseOrm::Base
  attribute :url, :string
  attribute :duration, :integer
end

class Post < CouchbaseOrm::Base
  embeds_one :media, polymorphic: true
end

# Using objects
post = Post.create!(media: Image.new(url: 'photo.jpg', caption: 'Sunset'))
post.media # => #<Image url: "photo.jpg", caption: "Sunset">

# Using hashes
post = Post.create!(media: { type: 'video', url: 'clip.mp4', duration: 120 })
post.media # => #<Video url: "clip.mp4", duration: 120>

embeds_many

class Article < CouchbaseOrm::Base
  embeds_many :attachments, polymorphic: ['ImageAttachment', 'VideoAttachment']
end

article = Article.create!(
  attachments: [
    { type: 'image_attachment', url: 'diagram.png' },
    { type: 'video_attachment', url: 'demo.mp4', duration: 90 }
  ]
)

article.attachments # => [#<ImageAttachment ...>, #<VideoAttachment ...>]

Files Changed

  • embeds_one.rb - Polymorphic support
  • embeds_many.rb - Polymorphic support
  • embeds_one_spec.rb - 17 new tests
  • embeds_many_spec.rb - 24 new tests
  • associations.txt - Documentation with examples

Tests

  • ✅ 111 tests passing (41 new polymorphic tests)
  • ✅ Type validation with objects and hashes
  • ✅ Persistence and retrieval
  • ✅ Type switching
  • ✅ Allowed types restrictions
  • ✅ Error handling

Database Storage

Type information is stored inside each embedded document:

embeds_one:

{
  "_id": "post::123",
  "media": {
    "type": "Image",
    "url": "photo.jpg",
    "caption": "Sunset"
  }
}

embeds_many:

{
  "_id": "article::456",
  "attachments": [
    {
      "type": "ImageAttachment",
      "url": "diagram.png",
      "caption": "Architecture"
    },
    {
      "type": "VideoAttachment",
      "url": "demo.mp4",
      "duration": 90
    }
  ]
}

Benefits

  • Clean, self-contained storage format
  • Type information travels with the data
  • No separate tracking fields needed
  • Easy to understand and debug

Made changes.

@giallon giallon self-assigned this Feb 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants