Callbacks
CQL's Active Record provides lifecycle callbacks that allow you to trigger logic at various points during an object's life. This is useful for tasks like data normalization before validation, encrypting passwords before saving, or sending notifications after an action.
The CQL::ActiveRecord::Callbacks module is automatically included when you use CQL::ActiveRecord::Model(Pk).
Available Callbacks
Callbacks are methods defined in your model that are registered to be called at specific moments. CQL supports the following callbacks:
Validation Callbacks:
before_validation(method_name): Called beforevalidateis run.after_validation(method_name): Called aftervalidatecompletes.
Save Callbacks (run for both create and update):
before_save(method_name): Called before the record is saved to the database.after_save(method_name): Called after the record is saved to the database.
Create Callbacks (run only when a new record is saved):
before_create(method_name): Called before a new record is inserted into the database.after_create(method_name): Called after a new record is inserted into the database.
Update Callbacks (run only when an existing record is saved):
before_update(method_name): Called before an existing record is updated in the database.after_update(method_name): Called after an existing record is updated in the database.
Destroy Callbacks:
before_destroy(method_name): Called before a record is deleted from the database.after_destroy(method_name): Called after a record is deleted from the database.
Registering Callbacks
You register a callback by calling its macro with the name of the method (as a Symbol) to be executed.
In this example:
normalize_emailwill run before validations.set_status_if_nilwill run before any save operation (create or update).send_welcome_emailwill run only after a new user is created.record_login_timewill run only before an existing user is updated.log_deletionwill run after a user is destroyed.
Halting Execution
If a before_validation, before_save, before_create, before_update, or before_destroy callback method returns false (explicitly false, not nil or other falsy values), the callback chain is halted. This means:
Subsequent callbacks of the same type (e.g., other
before_savemethods) will not be executed.The main action (validation, save, create, update, or destroy) will be canceled.
For
save,create,update, it will returnfalse.For
save!,create!,update!, it will not raiseRecordInvaliddue to validation errors (if any ran), but simply won't proceed with persistence.For
destroy, it will returnfalse, and the record will not be deleted.
Example of halting:
Important Notes:
after_*callbacks do not have the power to halt the chain, as the primary action has already completed.Only explicit
falsereturn values halt the chain.niland other falsy values do not halt execution.Multiple
before_*callbacks can be registered, and any of them can halt the chain.
Order of Callbacks
When multiple callbacks are registered for the same event, they are executed in the order they were defined in the model.
CQL follows a specific callback order during the save process:
before_validationValidations are run (
validatemethod)after_validationbefore_saveIf new record:
before_createIf existing record:
before_updateDatabase operation (INSERT or UPDATE)
If new record:
after_createIf existing record:
after_updateafter_save
For destroy:
before_destroyDatabase operation (DELETE)
after_destroy
Example showing the complete callback order:
Multiple Callbacks and Halting
You can register multiple callbacks for the same event, and any of them can halt the chain:
Use Cases and Best Practices
Common Use Cases
Data Manipulation: Normalize data (e.g., downcasing emails), set default values, generate tokens.
Lifecycle Management: Update related objects, log changes, manage state transitions.
Notifications: Send emails or push notifications after certain events (e.g.,
after_create).Conditional Logic: A callback method can contain logic to decide if it should perform an action, or even halt the entire operation.
Best Practices
Keep callbacks simple: Callbacks should be focused and not contain complex business logic.
Return values matter: Always return
truefrom callbacks unless you specifically want to halt the chain.Use private methods: Make callback methods private to indicate they're internal to the model.
Avoid side effects: Be careful with callbacks that modify other objects or make external API calls.
Test callbacks: Always test your callbacks to ensure they work as expected and don't cause unexpected behavior.
Consider alternatives: For complex logic, consider using service objects or other patterns instead of callbacks.
Anti-patterns to Avoid
Callbacks are a powerful tool for adding behavior to your models without cluttering your controller or service logic. However, use them judiciously, as complex callback chains can sometimes make debugging harder.
Last updated
Was this helpful?