Module: GraphMediator::DSL
- Includes:
- AliasExtension
- Defined in:
- lib/graph_mediator.rb
Overview
DSL for setting up and describing mediation.
save and save! are automatically wrapped for mediation when GraphMediator is included into your class. You can mediate other methods with a call to mediate(), and can setup callbacks for reconcilation, cacheing or version bumping.
Callbacks
The mediate() method takes options to set callbacks. Or you can set them directly with a method symbol, array of method symbols or a Proc. They may be called multiple times and may be added to in subclasses.
-
before_mediation - runs before mediation is begun
-
mediate and save
-
-
mediate_reconciles - after saveing the instance, run any routines to make further adjustments to the structure of the graph or non-cache attributes
-
mediate_caches - routines for updating cache values
Example:
mediate_reconciles :bar do |instance|
instance.something_else
end
mediate_reconciles :baz
will ensure that [:bar, <block>, :baz] are run in sequence after :foo is done saveing within the context of a mediated transaction.
Instance Method Summary collapse
-
#mediate(*methods) ⇒ Object
Establishes callbacks, dependencies and possible methods as entry points for mediation.
Methods included from Util
Instance Method Details
#mediate(*methods) ⇒ Object
Establishes callbacks, dependencies and possible methods as entry points for mediation.
-
:methods => list of methods to mediate (automatically wrap in a mediated_transaction call)
ActiveRecord::Base.save is decorated for mediation when GraphMediator is included into your model. If you have additional methods which perform bulk operations on members, you probably want to list them here so that they are mediated as well.
You should not list methods used for reconcilation, or cacheing.
This macro takes a number of options:
-
:options => hash of options
-
:dependencies => list of dependent member classes whose save methods should be decorated for mediation as well.
-
:when_reconciling => list of methods to execute during the after_mediation reconcilation phase
-
:when_cacheing => list of methods to execute during the after_mediation cacheing phase
-
mediate :update_children,
:dependencies => Child,
:when_reconciling => :reconcile,
:when_caching => :cache
Dependent Classes
Dependent classes have their save methods mediated as well. However, a dependent class must provide an accessor for the root node, so that a mediated_transaction can be begun in the root node when a dependent is changed. Dependent clases also have their destroy methods mediated so that destruction of a dependent also registers as a change to the graph.
Deletion and Dependents
When a class participating in mediation assigns a dependent to mediation, destruction of that dependent class will cause an update to the parent’s lock_version. This can cause a problem in Rails 2.3.6+ because ActiveRecord#destroy is wrapped with an optimistic locking check. When the dependent association is set to :dependent => :destroy, the dependents are automatically destroyed before the parent, which causes graph_mediator to update the lock_version of the parent, which then fails the optimistic locking check when it is sent for destruction in ActiveRecord::Locking::Optimistic#destroy_with_lock.
To avoid this, GraphMediator causes an activerecord instance to flag when it is in the process of destroying itself. This flag is then checked by dependents so they can bypass touching the parent when they are being destroyed.
Versioning and Optimistic Locking
GraphMediator uses the class’s lock_column (default lock_version
) and updated_at
or updated_on
for versioning and locks checks during mediation. The lock_column is incremented only once during a mediated_transaction.
Unless both these columns are present in the schema, versioning/locking will not happen. A lock_column by itself will not be updated unless there is an updated_at/on timestamp available to touch.
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
# File 'lib/graph_mediator.rb', line 578 def mediate(*methods) = methods. self.graph_mediator_dependencies = Array([:dependencies] || []) _register_for_mediation(*methods) graph_mediator_dependencies.each do |dependent_class| dependent_class.send(:extend, AliasExtension) unless dependent_class.include?(AliasExtension) methods = SAVE_METHODS.clone methods << :destroy methods << { :through => self.class_of_active_record_descendant(self).to_s.demodulize.underscore, :track_changes => true } dependent_class.send(:_register_for_mediation, *methods) end mediate_reconciles([:when_reconciling]) if [:when_reconciling] mediate_caches([:when_cacheing]) if [:when_cacheing] end |