user_interacted_project.rb 1.72 KB
Newer Older
1 2
# frozen_string_literal: true

Andreas Brandl's avatar
Andreas Brandl committed
3
class UserInteractedProject < ActiveRecord::Base
4 5 6
  belongs_to :user
  belongs_to :project

7 8
  validates :project_id, presence: true
  validates :user_id, presence: true
9

10 11
  CACHE_EXPIRY_TIME = 1.day

12 13 14
  # Schema version required for this model
  REQUIRED_SCHEMA_VERSION = 20180223120443

15 16 17 18 19
  class << self
    def track(event)
      # For events without a project, we simply don't care.
      # An example of this is the creation of a snippet (which
      # is not related to any project).
20
      return unless event.project_id
21 22 23 24 25 26 27

      attributes = {
        project_id: event.project_id,
        user_id: event.author_id
      }

      cached_exists?(attributes) do
28
        transaction(requires_new: true) do
Nick Thomas's avatar
Nick Thomas committed
29 30 31 32 33 34 35 36
          where(attributes).select(1).first || create!(attributes)
          true # not caching the whole record here for now
        rescue ActiveRecord::RecordNotUnique
          # Note, above queries are not atomic and prone
          # to race conditions (similar like #find_or_create!).
          # In the case where we hit this, the record we want
          # already exists - shortcut and return.
          true
37
        end
38 39 40
      end
    end

41 42 43 44 45
    # Check if we can safely call .track (table exists)
    def available?
      @available_flag ||= ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION # rubocop:disable Gitlab/PredicateMemoization
    end

46 47 48 49 50 51
    # Flushes cached information about schema
    def reset_column_information
      @available_flag = nil
      super
    end

52
    private
53

54
    def cached_exists?(project_id:, user_id:, &block)
55
      cache_key = "user_interacted_projects:#{project_id}:#{user_id}"
56 57
      Rails.cache.fetch(cache_key, expires_in: CACHE_EXPIRY_TIME, &block)
    end
58 59
  end
end