Module: UserGroupMembershipMixins::ValidityRangeForIndirectMemberships
- Extended by:
- ActiveSupport::Concern
- Included in:
- UserGroupMembership
- Defined in:
- app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb
Overview
In this project, user group memberships do not neccessarily last forever. They can begin at some time and end at some time. This is expressed by the ValidityRange of a membership.
Examples:
membership.valid_from # => time
membership.valid_to # => time
membership.invalidate
Scopes:
UserGroupMembership.with_invalid
UserGroupMembership.only_valid
UserGroupMembership.only_invalid
UserGroupMembership.at_time(time)
By default, the ‘only_valid` scope is applied, i.e. only memberships are found that are valid at present time. To override this scope, use either `with_invalid` or `unscoped`.
Instance Method Summary collapse
-
#earliest_direct_membership ⇒ Object
The validity range attributes are inherited for indirect memberships.
- #latest_direct_membership ⇒ Object
-
#make_invalid(time = Time.zone.now) ⇒ Object
For indirect memberships, invalidation is not possible.
-
#recalculate_validity_range_from_direct_memberships ⇒ Object
This method recalculates the validity range for an indirect membership.
- #recalculate_validity_range_from_direct_memberships! ⇒ Object
-
#save(*args) ⇒ Object
Save the current membership and auto-save also the direct memberships associated with the current (maybe indirect) membership.
- #valid_from ⇒ Object
- #valid_from=(valid_from) ⇒ Object
- #valid_to ⇒ Object
- #valid_to=(valid_to) ⇒ Object
Instance Method Details
#earliest_direct_membership ⇒ Object
The validity range attributes are inherited for indirect memberships.
*-----------------(c)--------------------*
|
|--------------------|
| |
*-------(a)--------* |
*---------(b)---------*
_________________________________________________________
t1 t2 t3 time -->
If membership A is valid from t1 to t2 and membership B is valid from t2 to t3 and membership C is the indirect membership that results from the memberships A and B, then C is valid from t1 to t3.
This means that the valid_from attribute is derived from the valid_from attribute of the earliest direct membership. The valid_to attribute is derived from the latest direct membership.
55 56 57 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 55 def earliest_direct_membership @earliest_direct_membership ||= direct_memberships(with_invalid: true).reorder('valid_from').first end |
#latest_direct_membership ⇒ Object
59 60 61 62 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 59 def latest_direct_membership @latest_direct_membership ||= direct_memberships.only_valid.last @latest_direct_membership ||= direct_memberships(with_invalid: true).reorder('valid_to').last end |
#make_invalid(time = Time.zone.now) ⇒ Object
For indirect memberships, invalidation is not possible. Only direct memberships can be invalidated. The validity of the indirect memberships inherts from the direct ones.
155 156 157 158 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 155 def make_invalid(time = Time.zone.now) raise 'An indirect membership cannot be invalidated. ' + self.user.id.to_s + ' ' + self.group.id.to_s unless direct? super end |
#recalculate_validity_range_from_direct_memberships ⇒ Object
This method recalculates the validity range for an indirect membership. This becomes necessary whenever the validity range of a direct membership is changed, so that the validity range of the indirect memberships can be used in database queries, for example, when using scopes.
Attention: At this point, this mechanism does not cover the validity range of indirect memberships where there should be a gap in the membership:
*----------* *----------* (indirect membership with gap in validity range)
|--------|--------|
*----------* | (direct membership 1)
*----------* (direct membership 2)
TODO: This has to be fiexed, probably when switching to neo4j.
114 115 116 117 118 119 120 121 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 114 def recalculate_validity_range_from_direct_memberships unless direct? write_attribute :valid_from, earliest_direct_membership.try(:valid_from) write_attribute :valid_to, latest_direct_membership.try(:valid_to) self.valid_from_will_change! self.valid_to_will_change! end end |
#recalculate_validity_range_from_direct_memberships! ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 123 def recalculate_validity_range_from_direct_memberships! unless direct? self.valid_from_will_change! self.valid_to_will_change! recalculate_validity_range_from_direct_memberships self.valid_from_will_change! self.valid_to_will_change! save! else raise "Recalculating the validity range makes only sense for indirect memberships. This is a direct one. Membership id: #{self.id}." end end |
#save(*args) ⇒ Object
Save the current membership and auto-save also the direct memberships associated with the current (maybe indirect) membership.
91 92 93 94 95 96 97 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 91 def save(*args) super(*args) unless self.direct? earliest_direct_membership.try(:save) latest_direct_membership.try(:save) end end |
#valid_from ⇒ Object
64 65 66 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 64 def valid_from self.direct? ? super : cached { earliest_direct_membership.try(:valid_from) } end |
#valid_from=(valid_from) ⇒ Object
67 68 69 70 71 72 73 74 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 67 def valid_from=( valid_from ) if self.direct? super(valid_from) @need_to_recalculate_indirect_memberships = true else earliest_direct_membership.try(:valid_from=, valid_from) end end |
#valid_to ⇒ Object
76 77 78 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 76 def valid_to self.direct? ? super : latest_direct_membership.try(:valid_to) end |
#valid_to=(valid_to) ⇒ Object
79 80 81 82 83 84 85 86 |
# File 'app/models/user_group_membership_mixins/validity_range_for_indirect_memberships.rb', line 79 def valid_to=( valid_to ) if self.direct? super(valid_to) @need_to_recalculate_indirect_memberships = true else latest_direct_membership.try(:valid_to=, valid_to) end end |