Class: ApplicationRecord

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
CrossDatabaseModification, DatabaseReflection, LegacyBulkInsert, SensitiveSerializableHash, Transactions
Defined in:
app/models/application_record.rb

Direct Known Subclasses

AbuseReport, AlertManagement::Alert, AlertManagement::AlertAssignee, AlertManagement::HttpIntegration, AlertManagement::MetricImage, Alerting::ProjectAlertingSetting, Analytics::CycleAnalytics::Aggregation, Analytics::CycleAnalytics::IssueStageEvent, Analytics::CycleAnalytics::MergeRequestStageEvent, Analytics::CycleAnalytics::ProjectStage, Analytics::CycleAnalytics::ProjectValueStream, Analytics::CycleAnalytics::StageEventHash, Analytics::UsageTrends::Measurement, Appearance, ApplicationSetting, ApplicationSetting::Term, Approval, Atlassian::Identity, AuditEvent, AuthenticationEvent, AwardEmoji, Aws::Role, Badge, Board, BoardGroupRecentVisit, BoardProjectRecentVisit, BroadcastMessage, BulkImport, BulkImports::Configuration, BulkImports::Entity, BulkImports::Export, BulkImports::ExportUpload, BulkImports::Failure, BulkImports::Tracker, ChatName, ChatTeam, Ci::ApplicationRecord, Ci::NamespaceMirror, Clusters::Agent, Clusters::AgentToken, Clusters::Agents::ActivityEvent, Clusters::Agents::GroupAuthorization, Clusters::Agents::ProjectAuthorization, Clusters::Applications::CertManager, Clusters::Applications::Cilium, Clusters::Applications::Crossplane, Clusters::Applications::ElasticStack, Clusters::Applications::Helm, Clusters::Applications::Ingress, Clusters::Applications::Jupyter, Clusters::Applications::Knative, Clusters::Applications::Prometheus, Clusters::Applications::Runner, Clusters::Cluster, Clusters::Group, Clusters::Integrations::ElasticStack, Clusters::Integrations::Prometheus, Clusters::KubernetesNamespace, Clusters::Platforms::Kubernetes, Clusters::Project, Clusters::Providers::Aws, Clusters::Providers::Gcp, CommitSignatures::GpgSignature, CommitSignatures::X509CommitSignature, ContainerExpirationPolicy, ContainerRepository, CustomEmoji, CustomerRelations::Contact, CustomerRelations::IssueContact, CustomerRelations::Organization, DependencyProxy::Blob, DependencyProxy::GroupSetting, DependencyProxy::ImageTtlGroupPolicy, DependencyProxy::Manifest, DeployKeysProject, DeployToken, Deployment, DeploymentCluster, DeploymentMergeRequest, DescriptionVersion, DesignManagement::Action, DesignManagement::Design, DesignManagement::Version, DevOpsReport::Metric, DiffNotePosition, DraftNote, Email, Environment, Epic, ErrorTracking::ClientKey, ErrorTracking::Error, ErrorTracking::ErrorEvent, ErrorTracking::ProjectErrorTrackingSetting, Event, Experiment, ExperimentSubject, ExperimentUser, ForkNetwork, ForkNetworkMember, Gitlab::BackgroundMigration::BackfillIntegrationsEnableSslVerification::Integration, Gitlab::BackgroundMigration::BackfillJiraTrackerDeploymentType2::JiraServiceTemp, Gitlab::BackgroundMigration::BackfillJiraTrackerDeploymentType2::JiraTrackerDataTemp, Gitlab::BackgroundMigration::BackfillWorkItemTypeIdForIssues::MigrationIssue, Gitlab::Database::PgUser, Gitlab::DatabaseImporters::CommonMetrics::PrometheusMetric, GpgKey, GpgKeySubkey, GrafanaIntegration, Group::CrmSettings, GroupCustomAttribute, GroupDeployKeysGroup, GroupDeployToken, GroupGroupLink, GroupImportState, Groups::FeatureSetting, Identity, ImportExportUpload, ImportFailure, IncidentManagement::IssuableEscalationStatus, IncidentManagement::ProjectIncidentManagementSetting, Integration, Integrations::IssueTrackerData, Integrations::JiraTrackerData, Integrations::ZentaoTrackerData, InternalId, IssuableSeverity, Issue, Issue::Email, Issue::Metrics, IssueAssignee, IssueEmailParticipant, IssueLink, Issues::CsvImport, Issues::SearchData, Iteration, JiraConnectInstallation, JiraConnectSubscription, JiraImportState, Key, Label, LabelLink, LabelPriority, LfsFileLock, LfsObject, LfsObjectsProject, List, ListUserPreference, Member, MemberTask, MergeRequest, MergeRequest::CleanupSchedule, MergeRequest::DiffCommitUser, MergeRequest::Metrics, MergeRequestAssignee, MergeRequestContextCommit, MergeRequestContextCommitDiffFile, MergeRequestDiff, MergeRequestDiffCommit, MergeRequestDiffFile, MergeRequestReviewer, MergeRequestsClosingIssues, Metrics::Dashboard::Annotation, Metrics::UsersStarredDashboard, Milestone, MilestoneRelease, Namespace, Namespace::AdminNote, Namespace::AggregationSchedule, Namespace::PackageSetting, Namespace::RootStorageStatistics, NamespaceSetting, NamespaceStatistics, Namespaces::SyncEvent, Note, NoteDiffFile, NotificationSetting, OnboardingProgress, Operations::FeatureFlag, Operations::FeatureFlags::Scope, Operations::FeatureFlags::Strategy, Operations::FeatureFlags::StrategyUserList, Operations::FeatureFlags::UserList, Operations::FeatureFlagsClient, Packages::BuildInfo, Packages::Cleanup::Policy, Packages::Composer::CacheFile, Packages::Composer::Metadatum, Packages::Conan::FileMetadatum, Packages::Conan::Metadatum, Packages::Debian::FileMetadatum, Packages::Debian::GroupArchitecture, Packages::Debian::GroupComponent, Packages::Debian::GroupComponentFile, Packages::Debian::GroupDistribution, Packages::Debian::GroupDistributionKey, Packages::Debian::ProjectArchitecture, Packages::Debian::ProjectComponent, Packages::Debian::ProjectComponentFile, Packages::Debian::ProjectDistribution, Packages::Debian::ProjectDistributionKey, Packages::Debian::Publication, Packages::Dependency, Packages::DependencyLink, Packages::Event, Packages::Helm::FileMetadatum, Packages::Maven::Metadatum, Packages::Npm::Metadatum, Packages::Nuget::DependencyLinkMetadatum, Packages::Nuget::Metadatum, Packages::Package, Packages::PackageFile, Packages::PackageFileBuildInfo, Packages::Pypi::Metadatum, Packages::Rubygems::Metadatum, Packages::Tag, PagesDeployment, PagesDomain, PagesDomainAcmeOrder, PersonalAccessToken, Plan, PlanLimits, PoolRepository, ProductAnalyticsEvent, ProgrammingLanguage, Project, ProjectAuthorization, ProjectAutoDevops, ProjectCiCdSetting, ProjectCustomAttribute, ProjectDailyStatistic, ProjectDeployToken, ProjectExportJob, ProjectFeature, ProjectFeatureUsage, ProjectGroupLink, ProjectImportData, ProjectImportState, ProjectMetricsSetting, ProjectPagesMetadatum, ProjectRepository, ProjectSetting, ProjectStatistics, ProjectTracingSetting, Projects::BuildArtifactsSizeRefresh, Projects::CiFeatureUsage, Projects::ProjectTopic, Projects::RepositoryStorageMove, Projects::SyncEvent, Projects::Topic, PrometheusAlert, PrometheusAlertEvent, PrometheusMetric, ProtectedBranch, ProtectedBranch::MergeAccessLevel, ProtectedBranch::PushAccessLevel, ProtectedTag, ProtectedTag::CreateAccessLevel, PushEventPayload, RawUsageData, RedirectRoute, Release, Releases::Evidence, Releases::Link, RemoteMirror, RepositoryLanguage, ResourceEvent, Review, Route, SelfManagedPrometheusAlertEvent, SentNotification, SentryIssue, Serverless::DomainCluster, ServiceDeskSetting, Shard, Snippet, SnippetRepository, SnippetStatistics, Snippets::RepositoryStorageMove, SpamLog, Subscription, Suggestion, SystemNoteMetadata, TermAgreement, Terraform::State, Terraform::StateVersion, Timelog, Todo, TokenWithIv, TrendingProject, U2fRegistration, Upload, User, UserAgentDetail, UserCanonicalEmail, UserCustomAttribute, UserDetail, UserHighestRole, UserInteractedProject, UserMention, UserPreference, UserStatus, UserSyncedAttributesMetadata, Users::BannedUser, Users::Callout, Users::CreditCardValidation, Users::GroupCallout, Users::InProductMarketingEmail, Users::SavedReply, Users::UserFollowUser, UsersStarProject, UsersStatistics, Vulnerability, WebHook, WebHookLog, WebauthnRegistration, WikiPage::Meta, WikiPage::Slug, WorkItems::Type, X509Certificate, X509Issuer, ZoomMeeting

Constant Summary collapse

MAX_PLUCK =

We should avoid using pluck docs.gitlab.com/ee/development/sql.html#plucking-ids but, if we are going to use it, let's try and limit the number of records

1_000

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SensitiveSerializableHash

#serializable_hash

Class Method Details

.cached_column_listObject


113
114
115
# File 'app/models/application_record.rb', line 113

def self.cached_column_list
  self.column_names.map { |column_name| self.arel_table[column_name] }
end

.declarative_enum(enum_mod) ⇒ Object


109
110
111
# File 'app/models/application_record.rb', line 109

def self.declarative_enum(enum_mod)
  enum(enum_mod.key => enum_mod.values)
end

.default_select_columnsObject


117
118
119
120
121
122
123
# File 'app/models/application_record.rb', line 117

def self.default_select_columns
  if ignored_columns.any?
    cached_column_list
  else
    arel_table[Arel.star]
  end
end

.id_in(ids) ⇒ Object


22
23
24
# File 'app/models/application_record.rb', line 22

def self.id_in(ids)
  where(id: ids)
end

.id_not_in(ids) ⇒ Object


34
35
36
# File 'app/models/application_record.rb', line 34

def self.id_not_in(ids)
  where.not(id: ids)
end

.iid_in(iids) ⇒ Object


30
31
32
# File 'app/models/application_record.rb', line 30

def self.iid_in(iids)
  where(iid: iids)
end

.pluck_primary_keyObject


38
39
40
# File 'app/models/application_record.rb', line 38

def self.pluck_primary_key
  where(nil).pluck(self.primary_key)
end

.primary_key_in(values) ⇒ Object


26
27
28
# File 'app/models/application_record.rb', line 26

def self.primary_key_in(values)
  where(primary_key => values)
end

.safe_ensure_unique(retries: 0) ⇒ Object


42
43
44
45
46
47
48
49
50
51
52
53
# File 'app/models/application_record.rb', line 42

def self.safe_ensure_unique(retries: 0)
  transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions
    yield
  end
rescue ActiveRecord::RecordNotUnique
  if retries > 0
    retries -= 1
    retry
  end

  false
end

.safe_find_or_create_by(*args, &block) ⇒ Object


77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/models/application_record.rb', line 77

def self.safe_find_or_create_by(*args, &block)
  record = find_by(*args)
  return record if record.present?

  # We need to use `all.create` to make this implementation follow `find_or_create_by` which delegates this in
  # https://github.com/rails/rails/blob/v6.1.3.2/activerecord/lib/active_record/querying.rb#L22
  #
  # When calling this method on an association, just calling `self.create` would call `ActiveRecord::Persistence.create`
  # and that skips some code that adds the newly created record to the association.
  transaction(requires_new: true) { all.create(*args, &block) } # rubocop:disable Performance/ActiveRecordSubtransactions
rescue ActiveRecord::RecordNotUnique
  find_by(*args)
end

.safe_find_or_create_by!(*args, &block) ⇒ Object


55
56
57
58
59
60
61
# File 'app/models/application_record.rb', line 55

def self.safe_find_or_create_by!(*args, &block)
  safe_find_or_create_by(*args, &block).tap do |record|
    raise ActiveRecord::RecordNotFound unless record.present?

    record.validate! unless record.persisted?
  end
end

.underscoreObject


97
98
99
# File 'app/models/application_record.rb', line 97

def self.underscore
  Gitlab::SafeRequestStore.fetch("model:#{self}:underscore") { self.to_s.underscore }
end

.where_exists(query) ⇒ Object


101
102
103
# File 'app/models/application_record.rb', line 101

def self.where_exists(query)
  where('EXISTS (?)', query.select(1))
end

.where_not_exists(query) ⇒ Object


105
106
107
# File 'app/models/application_record.rb', line 105

def self.where_not_exists(query)
  where('NOT EXISTS (?)', query.select(1))
end

.with_fast_read_statement_timeout(timeout_ms = 4500) ⇒ Object

Start a new transaction with a shorter-than-usual statement timeout. This is currently one third of the default 15-second timeout with a 500ms buffer to allow callers gracefully handling the errors to still complete within the 5s target duration of a low urgency request.


67
68
69
70
71
72
73
74
75
# File 'app/models/application_record.rb', line 67

def self.with_fast_read_statement_timeout(timeout_ms = 4500)
  ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
    transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions
      connection.exec_query("SET LOCAL statement_timeout = #{timeout_ms}")

      yield
    end
  end
end

.without_orderObject


18
19
20
# File 'app/models/application_record.rb', line 18

def self.without_order
  reorder(nil)
end

Instance Method Details

#create_or_load_association(association_name) ⇒ Object


91
92
93
94
95
# File 'app/models/application_record.rb', line 91

def create_or_load_association(association_name)
  association(association_name).create unless association(association_name).loaded?
rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation
  association(association_name).reader
end

#readable_by?(user) ⇒ Boolean

Returns:

  • (Boolean)

125
126
127
# File 'app/models/application_record.rb', line 125

def readable_by?(user)
  Ability.allowed?(user, "read_#{to_ability_name}".to_sym, self)
end

#to_ability_nameObject


129
130
131
# File 'app/models/application_record.rb', line 129

def to_ability_name
  model_name.element
end