class CQL::ActiveRecord::Relations::ManyCollection(Target, Through, Pk)

Overview

Enhanced collection class for many-to-many relationships with improved type safety, error handling, and performance optimizations.

A many-to-many association occurs when multiple records of one model can be associated with multiple records of another model, and vice versa. This requires a join table (or junction table) to store the relationships between the records of the two models.

Example

class Movie
  include CQL::ActiveRecord::Model(Int64)
  db_context AcmeDB, :movies

  property title : String = ""
  many_to_many :actors, Actor, join_through: MoviesActor

  def initialize(@title : String = "")
  end
end

class Actor
  include CQL::ActiveRecord::Model(Int64)
  db_context AcmeDB, :actors

  property name : String = ""

  def initialize(@name : String = "")
  end
end

class MoviesActor
  include CQL::ActiveRecord::Model(Int64)
  db_context AcmeDB, :movies_actors

  property movie_id : Int64?
  property actor_id : Int64?

  def initialize(@movie_id : Int64? = nil, @actor_id : Int64? = nil)
  end
end

movie = Movie.create!(title: "The Matrix")
movie.actors.create(name: "Keanu Reeves")
movie.actors.size # => 1

Defined in:

active_record/relations/many_collection.cr

Constructors

Instance Method Summary

Instance methods inherited from class CQL::ActiveRecord::Relations::Collection(Target, Pk)

<<(record : Target) <<, [](index : Int32) [], []?(index : Int32) []?, _inject_preloaded(records : Array(Target)) : Nil _inject_preloaded, all(type : T.class) : Array(T) forall T
all : Array(Target)
all
, all?(&block : Target -> Bool) all?, any?(&block : Target -> Bool) any?, build(**attributes) build, clear clear, concat(records : Array(Target)) : Array(Target) concat, count : Int64 count, create(record : Target)
create(**attributes)
create
, delete(record : Target)
delete(id : Pk)
delete
, delete_all : Int64 delete_all, each(&block : Target -> ) each, each_with_index(&block : Target, Int32 -> ) each_with_index, empty? empty?, exists?(**attributes) exists?, find(**attributes)
find(&block : Target -> Bool)
find
, find_by(**attributes) find_by, first first, first? first?, ids : Array(Pk) ids, ids=(ids : Array(Pk)) ids=, includes?(record : Target) : Bool includes?, last last, last? last?, length length, limit(limit_count : Int32) limit, loaded? : Bool loaded?, map(&block : Target -> U) forall U map, map_with_index(&block : Target, Int32 -> U) forall U map_with_index, nullify_all : Int64 nullify_all, offset(offset_count : Int32) offset, order(**order_by) order, reject(&block : Target -> Bool) reject, reload reload, remove(records : Array(Target)) : Array(Target) remove, select(&block : Target -> Bool) select, size size, to_a to_a, where(__sql sql : String, *positional, **named)
where(**conditions)
where

Constructor methods inherited from class CQL::ActiveRecord::Relations::Collection(Target, Pk)

new(key : Symbol, id : Pk, cascade : Bool = false, query base_query : CQL::Query | Nil = nil, auto_load : Bool = false, dependent : Symbol = :nullify) new

Macros inherited from module CQL::ActiveRecord::Relations::BaseRelation

build_query(model_class) build_query, destroy_dependent(record, association) destroy_dependent, ensure_saved(record) ensure_saved, safe_db_operation(&block) safe_db_operation, safe_foreign_key(record, key, pk_type) safe_foreign_key, safe_id(record, pk_type) safe_id, underscore_name(class_name) underscore_name

Constructor Detail

def self.new(key : Symbol, id : Pk, target_key : Symbol, cascade : Bool = false, query : CQL::Query | Nil = nil, dependent : Symbol = :nullify, validate : Bool = true, autosave : Bool = false) #

Initialize the many-to-many association collection class

  • param : key (Symbol) - The key for the parent record
  • param : id (Pk) - The id value for the parent record
  • param : target_key (Symbol) - The key for the associated record
  • param : cascade (Bool) - Delete associated records (deprecated, use dependent)
  • param : query (CQL::Query) - Query object
  • param : dependent (Symbol) - Dependency handling strategy
  • param : validate (Bool) - Whether to validate records
  • param : autosave (Bool) - Whether to automatically save records
  • return : ManyCollection

[View source]

Instance Method Detail

def <<(record : Target) #

Adds an existing record to the association. Creates the association in the join table. Raises an error if the target record is a new record.

  • param : record (Target)
  • return : self

[View source]
def build(**attributes) : Target #

Build a new target record but don't save it or create association

  • param : attributes (Hash | NamedTuple)
  • return : Target

[View source]
def clear #

Clears all associated records from the parent record. Removes associations from the join table and handles target records based on the dependent strategy.

  • return : self

[View source]
def clear_join_records #

Clear only the join table records (preserve target records)


[View source]
def clear_with_delete #

Clear associations and delete target records (without callbacks)


[View source]
def clear_with_destroy #

Clear associations and destroy target records


[View source]
def concat(records : Array(Target)) : Array(Target) #

Add multiple records to the association


[View source]
def create(record : Target) #

Associates an existing or new target record with the parent record. Creates the association in the join table. If the target record is new, it's created first.

  • param : record (Target) - The record to associate (can be new or persisted)
  • return : Target - The associated (and possibly created) record
  • raise : RelationError on creation failure

[View source]
def create(**attributes) #

Create a new target record with given attributes and associate it

  • param : attributes (Hash | NamedTuple)
  • return : Target
  • raise : RelationError on creation failure

[View source]
def delete(record : Target) : Target | Nil #

Deletes the association for the given record. For many-to-many relationships, this only removes the join table record.

  • param : record (Target)
  • return : Target? - The record if association was removed, nil otherwise

[View source]
def delete(id : Pk) : Target | Nil #

Deletes the association for the record with the given ID. For many-to-many relationships, this removes the join table record and handles the target record based on the dependent strategy.

  • param : id (Pk)
  • return : Target? - The target record if association was removed, nil otherwise

[View source]
def delete_all : Int64 #

Unlinks every associated record by deleting this parent's join rows. The records themselves stay, since they may belong to other parents; #clear with dependent: :delete_all or :destroy removes them too.

  • return : Int64 - Number of join rows deleted

[View source]
def exists?(**attributes) : Bool #

Checks if any records exist with the given attributes

  • param : attributes (NamedTuple)
  • return : Bool

[View source]
def find(**attributes) #

Override find to properly handle many-to-many relationships via join table

  • param : attributes (NamedTuple | Hash(Symbol, DB::Any))
  • return : Array(Target)

[View source]
def find_by(**attributes) #

Override find_by to properly handle many-to-many relationships via join table

  • param : attributes (NamedTuple | Hash(Symbol, DB::Any))
  • return : Target?

[View source]
def ids : Array(Pk) #

Get associated record IDs


[View source]
def ids=(ids : Array(Pk)) #

Set the associated record IDs (replaces current associations)


[View source]
def includes?(record : Target) : Bool #

Check if the collection includes a specific record


[View source]
def nullify_all : Int64 #

The link lives in the join table, so nullifying it deletes the join rows (same as #delete_all).

  • return : Int64 - Number of join rows deleted

[View source]
def remove(records : Array(Target)) : Array(Target) #

Remove multiple records from the association


[View source]