Class: Collavre::Creatives::PermissionCacheBuilder
- Inherits:
-
Object
- Object
- Collavre::Creatives::PermissionCacheBuilder
- Defined in:
- app/services/collavre/creatives/permission_cache_builder.rb
Class Method Summary collapse
-
.cache_owner(creative) ⇒ Object
Creative 생성 시 소유자 캐시 추가.
-
.propagate_share(creative_share) ⇒ Object
CreativeShare 생성/업데이트 시 호출.
-
.rebuild_for_creative(creative) ⇒ Object
Creative parent_id 변경 시 호출.
-
.rebuild_from_ancestors_for_user(creative, user_id) ⇒ Object
Public wrapper for rebuild_from_ancestors (used by PermissionCacheJob).
-
.rebuild_user_cache_for_subtree(creative, user_id) ⇒ Object
CreativeShare의 creative_id 또는 user_id 변경 시 이전 위치/사용자에 대해 호출 특정 사용자의 캐시를 서브트리에서 재구축 (조상 + 서브트리 내 직접 share 모두 고려) user_id는 nil (public share)일 수 있음.
-
.remove_share(creative_share) ⇒ Object
CreativeShare 삭제 시 호출.
-
.update_owner(creative, old_user_id, new_user_id) ⇒ Object
Creative user_id 변경 시 호출.
Class Method Details
.cache_owner(creative) ⇒ Object
Creative 생성 시 소유자 캐시 추가
5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 5 def self.cache_owner(creative) return unless creative.user_id CreativeSharesCache.upsert( { creative_id: creative.id, user_id: creative.user_id, permission: CreativeShare.[:admin], source_share_id: nil }, unique_by: [ :creative_id, :user_id ], update_only: [ :permission, :source_share_id ] ) end |
.propagate_share(creative_share) ⇒ Object
CreativeShare 생성/업데이트 시 호출
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 36 def self.propagate_share(creative_share) return if creative_share.destroyed? creative = creative_share.creative user_id = creative_share.user_id = creative_share. # 해당 creative + 모든 자손 ID (closure_tree 사용) all_descendant_ids = [ creative.id ] + creative.descendant_ids # "closest share wins" 의미론 적용: # 이 share의 자손 중 더 가까운 share가 있는 creative는 제외 # (더 가까운 share가 해당 서브트리를 담당) # no_access도 closer share로 인정 (public share보다 우선) closer_share_creative_ids = CreativeShare .where(user_id: user_id) .where(creative_id: creative.descendant_ids) # 이 creative의 strict descendants에 있는 share들 .where.not(id: creative_share.id) # 자기 자신 제외 .pluck(:creative_id) # 더 가까운 share가 있는 creative와 그 자손들은 제외 excluded_ids = Set.new if closer_share_creative_ids.any? excluded_ids = CreativeHierarchy .where(ancestor_id: closer_share_creative_ids) .pluck(:descendant_id) .to_set end ids_to_update = all_descendant_ids.reject { |id| excluded_ids.include?(id) } return if ids_to_update.empty? = CreativeShare.[] # Handle NULL user_id (public shares) separately since SQLite treats NULL as distinct in unique indexes if user_id.nil? ids_to_update.each do |cid| CreativeSharesCache.find_or_initialize_by(creative_id: cid, user_id: nil).tap do |cache| cache.assign_attributes( permission: , source_share_id: creative_share.id ) cache.save! end end else records = ids_to_update.map do |cid| { creative_id: cid, user_id: user_id, permission: , source_share_id: creative_share.id } end # Single bulk operation instead of N individual saves CreativeSharesCache.upsert_all( records, unique_by: [ :creative_id, :user_id ], update_only: [ :permission, :source_share_id ] ) end end |
.rebuild_for_creative(creative) ⇒ Object
Creative parent_id 변경 시 호출
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 137 def self.rebuild_for_creative(creative) descendant_ids = creative.self_and_descendant_ids # 해당 creative와 자손들의 캐시 삭제 (share 기반만 - owner entries 유지) CreativeSharesCache.where(creative_id: descendant_ids) .where.not(source_share_id: nil) .delete_all # 새 부모 기준으로 조상 share 전파 rebuild_from_ancestors_for_subtree(creative) # 이동된 서브트리 내의 직접 share들 재적용 # (closest-share-wins 의미론으로 올바르게 전파됨) # no_access도 포함 - 캐시에 저장하여 public share를 override CreativeShare.where(creative_id: descendant_ids) .find_each { |share| propagate_share(share) } # 소유자 캐시 재확인 (혹시 누락된 경우) creative.self_and_descendants.each do |c| cache_owner(c) if c.user_id end end |
.rebuild_from_ancestors_for_user(creative, user_id) ⇒ Object
Public wrapper for rebuild_from_ancestors (used by PermissionCacheJob)
110 111 112 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 110 def self.rebuild_from_ancestors_for_user(creative, user_id) rebuild_from_ancestors(creative, user_id) end |
.rebuild_user_cache_for_subtree(creative, user_id) ⇒ Object
CreativeShare의 creative_id 또는 user_id 변경 시 이전 위치/사용자에 대해 호출특정 사용자의 캐시를 서브트리에서 재구축 (조상 + 서브트리 내 직접 share 모두 고려) user_id는 nil (public share)일 수 있음
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 117 def self.rebuild_user_cache_for_subtree(creative, user_id) return unless creative descendant_ids = [ creative.id ] + creative.descendant_ids # 해당 사용자의 캐시만 삭제 (owner entries 유지를 위해 source_share_id가 있는 것만) CreativeSharesCache.where(creative_id: descendant_ids, user_id: user_id) .where.not(source_share_id: nil) .delete_all # 조상에서 해당 사용자의 share 찾아서 전파 rebuild_from_ancestors(creative, user_id) # 서브트리 내의 해당 사용자 직접 share들도 재적용 # no_access도 포함 - 캐시에 저장하여 public share를 override CreativeShare.where(creative_id: descendant_ids, user_id: user_id) .find_each { |share| propagate_share(share) } end |
.remove_share(creative_share) ⇒ Object
CreativeShare 삭제 시 호출
102 103 104 105 106 107 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 102 def self.remove_share(creative_share) CreativeSharesCache.where(source_share_id: creative_share.id).delete_all # 삭제 후 조상에서 다른 share가 있으면 다시 전파 rebuild_from_ancestors(creative_share.creative, creative_share.user_id) end |
.update_owner(creative, old_user_id, new_user_id) ⇒ Object
Creative user_id 변경 시 호출
21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'app/services/collavre/creatives/permission_cache_builder.rb', line 21 def self.update_owner(creative, old_user_id, new_user_id) # 기존 소유자의 owner 캐시 삭제 (source_share_id가 nil인 것만) if old_user_id CreativeSharesCache.where( creative_id: creative.id, user_id: old_user_id, source_share_id: nil ).delete_all end # 새 소유자 캐시 추가 cache_owner(creative) if new_user_id end |