diff --git a/docs/reference/associations.txt b/docs/reference/associations.txt index b2ca1117..9aedbeed 100644 --- a/docs/reference/associations.txt +++ b/docs/reference/associations.txt @@ -12,6 +12,329 @@ Associations :depth: 2 :class: singlecol +Embedded Associations +===================== + +CouchbaseOrm supports embedding documents within a parent document using +``embeds_one`` and ``embeds_many``. Unlike referenced associations, embedded +documents are stored directly within the parent document and do not have their +own separate document ID in the database. This is useful for modeling +has-one and has-many relationships where the child documents don't need to exist +independently. + +Embeds One +---------- + +Use the ``embeds_one`` association to declare that the parent embeds a single +child document: + +.. code-block:: ruby + + class Profile < CouchbaseOrm::Base + attribute :bio, :string + attribute :website, :string + end + + class User < CouchbaseOrm::Base + attribute :name, :string + embeds_one :profile + end + + user = User.create!(name: 'Alice', profile: { bio: 'Software Engineer' }) + # => # + + user.profile + # => # + + user.profile.bio = 'Senior Software Engineer' + user.profile = user.profile # Reassign to track changes + user.save! + +The embedded document is stored as a hash within the parent: + +.. code-block:: ruby + + # In the database, the document looks like: + { + "_id": "user::123", + "name": "Alice", + "profile": { + "bio": "Software Engineer", + "website": null + } + } + +Embedded documents cannot be saved, destroyed, or reloaded independently: + +.. code-block:: ruby + + user.profile.save + # => raises "Cannot save an embedded document!" + +Embeds Many +----------- + +Use the ``embeds_many`` association to declare that the parent embeds multiple +child documents: + +.. code-block:: ruby + + class Address < CouchbaseOrm::Base + attribute :street, :string + attribute :city, :string + end + + class Person < CouchbaseOrm::Base + attribute :name, :string + embeds_many :addresses + end + + person = Person.create!( + name: 'Bob', + addresses: [ + { street: '123 Main St', city: 'New York' }, + { street: '456 Elm St', city: 'Boston' } + ] + ) + + person.addresses + # => [#
, + # #
] + + person.addresses << Address.new(street: '789 Oak Ave', city: 'Chicago') + person.addresses = person.addresses # Reassign to track changes + person.save! + +Polymorphic Embedded Associations +---------------------------------- + +Both ``embeds_one`` and ``embeds_many`` support polymorphic associations, +allowing you to embed different types of documents in the same association: + +.. code-block:: ruby + + 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 + + # Embed an image using an object + post = Post.create!(media: Image.new(url: 'photo.jpg', caption: 'Sunset')) + post.media + # => # + + # Or use a hash with type key (snake_case class name) + post = Post.create!(media: { type: 'image', url: 'photo.jpg', caption: 'Sunset' }) + + # Switch to a video + post.media = Video.new(url: 'clip.mp4', duration: 120) + post.save! + +For ``embeds_many`` with polymorphism: + +.. code-block:: ruby + + class Article < CouchbaseOrm::Base + embeds_many :attachments, polymorphic: true + end + + # Using objects + article = Article.create!( + attachments: [ + Image.new(url: 'diagram.png', caption: 'Architecture'), + Video.new(url: 'demo.mp4', duration: 90) + ] + ) + + # Or using hashes with type key (snake_case class names) + article = Article.create!( + attachments: [ + { type: 'image', url: 'diagram.png', caption: 'Architecture' }, + { type: 'video', url: 'demo.mp4', duration: 90 } + ] + ) + + article.attachments + # => [#, #