73 lines
1.7 KiB
Ruby
73 lines
1.7 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
# This class is a simplified version of assign_nested_attributes_for_collection_association from ActiveRecord
|
||
|
# https://github.com/rails/rails/blob/v6.0.2.1/activerecord/lib/active_record/nested_attributes.rb#L466
|
||
|
|
||
|
module Ci
|
||
|
class UpdateInstanceVariablesService
|
||
|
UNASSIGNABLE_KEYS = %w(id _destroy).freeze
|
||
|
|
||
|
def initialize(params)
|
||
|
@params = params[:variables_attributes]
|
||
|
end
|
||
|
|
||
|
def execute
|
||
|
instantiate_records
|
||
|
persist_records
|
||
|
end
|
||
|
|
||
|
def errors
|
||
|
@records.to_a.flat_map { |r| r.errors.full_messages }
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
attr_reader :params
|
||
|
|
||
|
def existing_records_by_id
|
||
|
@existing_records_by_id ||= Ci::InstanceVariable
|
||
|
.all
|
||
|
.index_by { |var| var.id.to_s }
|
||
|
end
|
||
|
|
||
|
def instantiate_records
|
||
|
@records = params.map do |attributes|
|
||
|
find_or_initialize_record(attributes).tap do |record|
|
||
|
record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
|
||
|
record.mark_for_destruction if has_destroy_flag?(attributes)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def find_or_initialize_record(attributes)
|
||
|
id = attributes[:id].to_s
|
||
|
|
||
|
if id.blank?
|
||
|
Ci::InstanceVariable.new
|
||
|
else
|
||
|
existing_records_by_id.fetch(id) { raise ActiveRecord::RecordNotFound }
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def persist_records
|
||
|
Ci::InstanceVariable.transaction do
|
||
|
success = @records.map do |record|
|
||
|
if record.marked_for_destruction?
|
||
|
record.destroy
|
||
|
else
|
||
|
record.save
|
||
|
end
|
||
|
end.all?
|
||
|
|
||
|
raise ActiveRecord::Rollback unless success
|
||
|
|
||
|
success
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def has_destroy_flag?(hash)
|
||
|
Gitlab::Utils.to_boolean(hash['_destroy'])
|
||
|
end
|
||
|
end
|
||
|
end
|