Cache relationships in API (#6482)
* Cache relationships in API * Fetch relationships for search results in UI * Only save one account's maps in each cache item
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| import api from '../api'; | ||||
| import { fetchRelationships } from './accounts'; | ||||
|  | ||||
| export const SEARCH_CHANGE = 'SEARCH_CHANGE'; | ||||
| export const SEARCH_CLEAR  = 'SEARCH_CLEAR'; | ||||
| @@ -38,6 +39,7 @@ export function submitSearch() { | ||||
|       }, | ||||
|     }).then(response => { | ||||
|       dispatch(fetchSearchSuccess(response.data)); | ||||
|       dispatch(fetchRelationships(response.data.accounts.map(item => item.id))); | ||||
|     }).catch(error => { | ||||
|       dispatch(fetchSearchFail(error)); | ||||
|     }); | ||||
|   | ||||
| @@ -16,12 +16,16 @@ class AccountDomainBlock < ApplicationRecord | ||||
|   belongs_to :account | ||||
|   validates :domain, presence: true, uniqueness: { scope: :account_id } | ||||
|  | ||||
|   after_create  :remove_blocking_cache | ||||
|   after_destroy :remove_blocking_cache | ||||
|   after_commit :remove_blocking_cache | ||||
|   after_commit :remove_relationship_cache | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def remove_blocking_cache | ||||
|     Rails.cache.delete("exclude_domains_for:#{account_id}") | ||||
|   end | ||||
|  | ||||
|   def remove_relationship_cache | ||||
|     Rails.cache.delete_matched("relationship:#{account_id}:*") | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -12,14 +12,14 @@ | ||||
|  | ||||
| class Block < ApplicationRecord | ||||
|   include Paginable | ||||
|   include RelationshipCacheable | ||||
|  | ||||
|   belongs_to :account | ||||
|   belongs_to :target_account, class_name: 'Account' | ||||
|  | ||||
|   validates :account_id, uniqueness: { scope: :target_account_id } | ||||
|  | ||||
|   after_create  :remove_blocking_cache | ||||
|   after_destroy :remove_blocking_cache | ||||
|   after_commit :remove_blocking_cache | ||||
|  | ||||
|   private | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								app/models/concerns/relationship_cacheable.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/models/concerns/relationship_cacheable.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| module RelationshipCacheable | ||||
|   extend ActiveSupport::Concern | ||||
|  | ||||
|   included do | ||||
|     after_commit :remove_relationship_cache | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def remove_relationship_cache | ||||
|     Rails.cache.delete("relationship:#{account_id}:#{target_account_id}") | ||||
|     Rails.cache.delete("relationship:#{target_account_id}:#{account_id}") | ||||
|   end | ||||
| end | ||||
| @@ -13,6 +13,7 @@ | ||||
|  | ||||
| class Follow < ApplicationRecord | ||||
|   include Paginable | ||||
|   include RelationshipCacheable | ||||
|  | ||||
|   belongs_to :account, counter_cache: :following_count | ||||
|  | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
|  | ||||
| class FollowRequest < ApplicationRecord | ||||
|   include Paginable | ||||
|   include RelationshipCacheable | ||||
|  | ||||
|   belongs_to :account | ||||
|   belongs_to :target_account, class_name: 'Account' | ||||
|   | ||||
| @@ -13,14 +13,14 @@ | ||||
|  | ||||
| class Mute < ApplicationRecord | ||||
|   include Paginable | ||||
|   include RelationshipCacheable | ||||
|  | ||||
|   belongs_to :account | ||||
|   belongs_to :target_account, class_name: 'Account' | ||||
|  | ||||
|   validates :account_id, uniqueness: { scope: :target_account_id } | ||||
|  | ||||
|   after_create  :remove_blocking_cache | ||||
|   after_destroy :remove_blocking_cache | ||||
|   after_commit :remove_blocking_cache | ||||
|  | ||||
|   private | ||||
|  | ||||
|   | ||||
| @@ -5,11 +5,67 @@ class AccountRelationshipsPresenter | ||||
|               :muting, :requested, :domain_blocking | ||||
|  | ||||
|   def initialize(account_ids, current_account_id, **options) | ||||
|     @following       = Account.following_map(account_ids, current_account_id).merge(options[:following_map] || {}) | ||||
|     @followed_by     = Account.followed_by_map(account_ids, current_account_id).merge(options[:followed_by_map] || {}) | ||||
|     @blocking        = Account.blocking_map(account_ids, current_account_id).merge(options[:blocking_map] || {}) | ||||
|     @muting          = Account.muting_map(account_ids, current_account_id).merge(options[:muting_map] || {}) | ||||
|     @requested       = Account.requested_map(account_ids, current_account_id).merge(options[:requested_map] || {}) | ||||
|     @domain_blocking = Account.domain_blocking_map(account_ids, current_account_id).merge(options[:domain_blocking_map] || {}) | ||||
|     @account_ids        = account_ids.map { |a| a.is_a?(Account) ? a.id : a } | ||||
|     @current_account_id = current_account_id | ||||
|  | ||||
|     @following       = cached[:following].merge(Account.following_map(@uncached_account_ids, @current_account_id)) | ||||
|     @followed_by     = cached[:followed_by].merge(Account.followed_by_map(@uncached_account_ids, @current_account_id)) | ||||
|     @blocking        = cached[:blocking].merge(Account.blocking_map(@uncached_account_ids, @current_account_id)) | ||||
|     @muting          = cached[:muting].merge(Account.muting_map(@uncached_account_ids, @current_account_id)) | ||||
|     @requested       = cached[:requested].merge(Account.requested_map(@uncached_account_ids, @current_account_id)) | ||||
|     @domain_blocking = cached[:domain_blocking].merge(Account.domain_blocking_map(@uncached_account_ids, @current_account_id)) | ||||
|  | ||||
|     cache_uncached! | ||||
|  | ||||
|     @following.merge!(options[:following_map] || {}) | ||||
|     @followed_by.merge!(options[:followed_by_map] || {}) | ||||
|     @blocking.merge!(options[:blocking_map] || {}) | ||||
|     @muting.merge!(options[:muting_map] || {}) | ||||
|     @requested.merge!(options[:requested_map] || {}) | ||||
|     @domain_blocking.merge!(options[:domain_blocking_map] || {}) | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def cached | ||||
|     return @cached if defined?(@cached) | ||||
|  | ||||
|     @cached = { | ||||
|       following: {}, | ||||
|       followed_by: {}, | ||||
|       blocking: {}, | ||||
|       muting: {}, | ||||
|       requested: {}, | ||||
|       domain_blocking: {}, | ||||
|     } | ||||
|  | ||||
|     @uncached_account_ids = [] | ||||
|  | ||||
|     @account_ids.each do |account_id| | ||||
|       maps_for_account = Rails.cache.read("relationship:#{@current_account_id}:#{account_id}") | ||||
|  | ||||
|       if maps_for_account.is_a?(Hash) | ||||
|         @cached.merge!(maps_for_account) | ||||
|       else | ||||
|         @uncached_account_ids << account_id | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     @cached | ||||
|   end | ||||
|  | ||||
|   def cache_uncached! | ||||
|     @uncached_account_ids.each do |account_id| | ||||
|       maps_for_account = { | ||||
|         following:       { account_id => following[account_id] }, | ||||
|         followed_by:     { account_id => followed_by[account_id] }, | ||||
|         blocking:        { account_id => blocking[account_id] }, | ||||
|         muting:          { account_id => muting[account_id] }, | ||||
|         requested:       { account_id => requested[account_id] }, | ||||
|         domain_blocking: { account_id => domain_blocking[account_id] }, | ||||
|       } | ||||
|  | ||||
|       Rails.cache.write("relationship:#{@current_account_id}:#{account_id}", maps_for_account, expires_in: 1.day) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user