Class: ProjectAuthorization
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- ProjectAuthorization
- Extended by:
- SuppressCompositePrimaryKeyWarning
- Defined in:
- app/models/project_authorization.rb
Constant Summary
Constants inherited from ApplicationRecord
Constants included from HasCheckConstraints
HasCheckConstraints::NOT_NULL_CHECK_PATTERN
Constants included from ResetOnColumnErrors
ResetOnColumnErrors::MAX_RESET_PERIOD
Class Method Summary collapse
- .find_or_create_authorization_for(user_id, project_id, access_level) ⇒ Object
-
.insert_all(attributes) ⇒ Object
This method overrides its ActiveRecord’s version in order to work correctly with composite primary keys and fix the tests for Rails 6.1.
- .select_from_union(relations) ⇒ Object
Methods inherited from ApplicationRecord
===, cached_column_list, #create_or_load_association, current_transaction, declarative_enum, default_select_columns, delete_all_returning, #deleted_from_database?, id_in, id_not_in, iid_in, nullable_column?, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order
Methods included from ResetOnColumnErrors
#reset_on_union_error, #reset_on_unknown_attribute_error
Methods included from Gitlab::SensitiveSerializableHash
Class Method Details
.find_or_create_authorization_for(user_id, project_id, access_level) ⇒ Object
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 |
# File 'app/models/project_authorization.rb', line 44 def self.(user_id, project_id, access_level) # We only try to find the record by user and project so that we match the current model level validation and # database constraints. # Ideally, in the case where a record exists with a different access_level, # this will save us from performing an unnecessary upsert that will hit the `ON CONFLICT DO NOTHING` path. # Due to the nature of project authorizations, differences in access_level should be handled by the # recalculation service/workers and not anything that invokes this method. find_by(user_id: user_id, project_id: project_id) || # If not, we try to create it with `upsert`. # We use upsert for these reasons: # - No subtransactions # - Due to the use of `on_duplicate: :skip`, we are essentially issuing a `ON CONFLICT DO NOTHING`. # - Postgres will take care of skipping the record without errors if a similar record was created # by then in another thread. # - There is no explicit error being thrown because we said "ON CONFLICT DO NOTHING". # With this we avoid both the problems with subtransactions that could arise when we upgrade Rails, # see https://gitlab.com/gitlab-org/gitlab/-/issues/439567, and also with race conditions. upsert( { project_id: project_id, user_id: user_id, access_level: access_level, is_unique: true }, unique_by: [:project_id, :user_id], # skip unique_by access_level here to avoid conflicting access. on_duplicate: :skip # Do not change access_level, could cause conflicting permissions. ) end |
.insert_all(attributes) ⇒ Object
This method overrides its ActiveRecord’s version in order to work correctly with composite primary keys and fix the tests for Rails 6.1
Consider using BulkInsertSafe module instead since we plan to refactor it in gitlab.com/gitlab-org/gitlab/-/issues/331264
40 41 42 |
# File 'app/models/project_authorization.rb', line 40 def self.insert_all(attributes) super(attributes, unique_by: connection.schema_cache.primary_keys(table_name)) end |
.select_from_union(relations) ⇒ Object
29 30 31 32 33 |
# File 'app/models/project_authorization.rb', line 29 def self.select_from_union(relations) from_union(relations) .select(['project_id', 'MAX(access_level) AS access_level']) .group(:project_id) end |