Ralph::Associations
Associations module for defining model relationships
This module provides macros for defining common database associations:
belongs_to- Many-to-one relationship (e.g., a post belongs to a user)has_one- One-to-one relationship (e.g., a user has one profile)has_many- One-to-many relationship (e.g., a user has many posts)
Polymorphic associations are also supported:
belongs_to commentable : Model, polymorphic: true- Can belong to multiple model typeshas_many comments : Comment, as: :commentable- Parent side of polymorphic relationship
New in Phase 3.3:
counter_cache: true- Maintain a count column on parent for has_many associationstouch: true- Update parent timestamp when association changes- Association scoping with lambda blocks
- Through associations:
has_many tags : Tag, through: :posts
Example:
class Post < Ralph::Model
column id : Int64, primary: true
column title : String
column user_id : Int64
belongs_to user : User, touch: true
end
class User < Ralph::Model
column id : Int64, primary: true
column name : String
column posts_count : Int32, default: 0
column updated_at : Time?
has_one profile : Profile
has_many posts : Post, counter_cache: true
has_many tags : Tag, through: :posts
end
Class methods
Get counter caches for a child class
Lookup and find a polymorphic record by class name and id (as string) The id is passed as a string to support flexible primary key types
Register a counter cache relationship
Register a model class for polymorphic lookup
This is called at runtime when models with as: option are loaded
Uses String for flexible primary key type support (Int64, UUID, String, etc.)
Macros
Define a belongs_to association
Options:
- foreign_key: Specify a custom foreign key column (e.g., "author_id" instead of "user_id")
- primary_key: Specify the primary key on the associated model (defaults to "id")
- touch: If true, updates parent's updated_at on save; can also be a column name
- counter_cache: If true, maintains a count column on the parent model
- true: Uses default column name (e.g.,
posts_countforbelongs_to Post) - String: Uses custom column name (e.g.,
counter_cache: "comment_count")
- true: Uses default column name (e.g.,
- optional: If true, the foreign key can be nil (default: false)
For polymorphic associations, use the special form: belongs_to polymorphic: :commentable
Supports two syntaxes: belongs_to User # Association name inferred as 'user' belongs_to author : User # Explicit association name
Usage:
belongs_to User # user, user_id
belongs_to author : User # author, author_id (explicit name)
belongs_to author : User, foreign_key: :writer_id # author, writer_id
belongs_to User, primary_key: :uuid # user, user_id (looks up by uuid)
belongs_to polymorphic: :commentable # commentable_id, commentable_type columns
belongs_to User, touch: true # Updates user.updated_at on save
belongs_to User, touch: :last_post_at # Updates user.last_post_at on save
belongs_to User, counter_cache: true # Maintains user.posts_count
belongs_to User, counter_cache: "total_books" # Uses custom column name
Define a has_many association
Options:
- foreign_key: Specify a custom foreign key on the associated model (e.g., "owner_id" instead of "user_id")
- primary_key: Specify the primary key on this model (defaults to "id")
- polymorphic: For polymorphic associations, specify the name of the polymorphic interface on the child
- through: For through associations, specify the intermediate association name
- source: For through associations, specify the source association on the through model
- dependent: Specify what happens to associated records when this record is destroyed
- :destroy - Destroy associated records (runs callbacks)
- :delete_all - Delete associated records (skips callbacks)
- :nullify - Set foreign key to NULL
- :restrict_with_error - Prevent destruction if associations exist (adds error)
- :restrict_with_exception - Prevent destruction if associations exist (raises exception)
Note: For counter caching, use counter_cache: true on the belongs_to side of the association.
This automatically generates increment/decrement/update callbacks on the child model.
Supports two syntaxes: has_many Post # Association name inferred as 'posts' has_many posts : Post # Explicit association name
Usage:
has_many Post # posts
has_many articles : Post # articles (explicit name)
has_many articles : BlogPost, foreign_key: :writer_id # articles, writer_id
has_many Post, dependent: :destroy # destroys posts when parent destroyed
has_many Post, dependent: :delete_all # deletes without callbacks
has_many comments : Comment, polymorphic: :commentable # polymorphic (Comment has commentable_id/type)
has_many tags : Tag, through: :post_tags # through association
has_many tags : Tag, through: :post_tags, source: :tag # through with custom source
Define a has_one association
Options:
- foreign_key: Specify a custom foreign key on the associated model (e.g., "owner_id" instead of "user_id")
- primary_key: Specify the primary key on this model (defaults to "id")
- polymorphic: For polymorphic associations, specify the name of the polymorphic interface on the child
- dependent: Specify what happens to associated records when this record is destroyed
- :destroy - Destroy associated records (runs callbacks)
- :delete - Delete associated records (skips callbacks)
- :nullify - Set foreign key to NULL
- :restrict_with_error - Prevent destruction if associations exist (adds error)
- :restrict_with_exception - Prevent destruction if associations exist (raises exception)
Supports two syntaxes: has_one Profile # Association name inferred as 'profile' has_one user_profile : Profile # Explicit association name
Usage:
has_one Profile # profile
has_one user_profile : Profile # user_profile (explicit name)
has_one avatar : UserAvatar, foreign_key: :owner_id # avatar, owner_id on UserAvatar
has_one Profile, dependent: :destroy # destroys profile when user destroyed
has_one profile : Profile, polymorphic: :profileable # polymorphic (Profile has profileable_id/type)