Class: Scimitar::ActiveRecordBackedResourcesController

Inherits:
ResourcesController show all
Defined in:
app/controllers/scimitar/active_record_backed_resources_controller.rb

Overview

An ActiveRecord-centric subclass of Scimitar::ResourcesController. See that class’s documentation first, as it describes things that your subclass must do which apply equally to subclasses of this ActiveRecord-focused code.

In addition to requirements mentioned above, your subclass MUST override protected method #storage_scope, returning an ActiveRecord::Relation which is used as a starting scope for any ‘index’ (list) views. This gives you an opportunity to apply things like is-active filters, apply soft deletion scopes, apply security scopes and so-on. For example:

protected
  def storage_scope
    self.storage_class().where(is_deleted: false)
  end

Instance Method Summary collapse

Instance Method Details

#create(&block) ⇒ Object

POST (create)

Calls #save! on the new record if no block is given, else invokes the block, passing it the new ActiveRecord model instance to be saved. It is up to the block to make any further changes and persist the record.

Blocks are invoked from within a wrapping database transaction. ActiveRecord::RecordInvalid exceptions are handled for you, rendering an appropriate SCIM error.



75
76
77
78
79
80
81
82
83
84
# File 'app/controllers/scimitar/active_record_backed_resources_controller.rb', line 75

def create(&block)
  super do |scim_resource|
    self.storage_class().transaction do
      record = self.storage_class().new
      record.from_scim!(scim_hash: scim_resource.as_json())
      self.save!(record, &block)
      record_to_scim(record)
    end
  end
end

#destroy(&block) ⇒ Object

DELETE (remove)

Deletion methods can vary quite a lot with ActiveRecord objects. If you just let this superclass handle things, it’ll call:

https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-destroy-21

…i.e. the standard delete-record-with-callbacks method. If you pass a block, then this block is invoked and passed the ActiveRecord model instance to be destroyed. You can then do things like soft-deletions, updating an “active” flag, perform audit-related operations and so-on.



132
133
134
135
136
137
138
139
140
141
142
# File 'app/controllers/scimitar/active_record_backed_resources_controller.rb', line 132

def destroy(&block)
  super do |record_id|
    record = self.find_record(record_id)

    if block_given?
      yield(record)
    else
      record.destroy!
    end
  end
end

#indexObject

GET (list)



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/controllers/scimitar/active_record_backed_resources_controller.rb', line 26

def index
  query = if params[:filter].blank?
    self.storage_scope()
  else
    attribute_map = storage_class().new.scim_queryable_attributes()
    parser        = ::Scimitar::Lists::QueryParser.new(attribute_map)

    parser.parse(params[:filter])
    parser.to_activerecord_query(self.storage_scope())
  end

  pagination_info = scim_pagination_info(query.count())

  # SCIM 2.0 RFC 7644: When count=0, return metadata only (no Resources).
  # This avoids an unnecessary database query for record data.
  page_of_results = if pagination_info.limit == 0
    []
  else
    query
      .order(@id_column => :asc)
      .offset(pagination_info.offset)
      .limit(pagination_info.limit)
      .to_a()
  end

  super(pagination_info, page_of_results) do | record |
    record_to_scim(record)
  end
end

#replace(&block) ⇒ Object

PUT (replace)

Calls #save! on the updated record if no block is given, else invokes the block, passing the updated record which the block must persist, with the same rules as for #create.



92
93
94
95
96
97
98
99
100
101
# File 'app/controllers/scimitar/active_record_backed_resources_controller.rb', line 92

def replace(&block)
  super do |record_id, scim_resource|
    self.storage_class().transaction do
      record = self.find_record(record_id)
      record.from_scim!(scim_hash: scim_resource.as_json())
      self.save!(record, &block)
      record_to_scim(record)
    end
  end
end

#showObject

GET/id (show)



58
59
60
61
62
63
# File 'app/controllers/scimitar/active_record_backed_resources_controller.rb', line 58

def show
  super do |record_id|
    record = self.find_record(record_id)
    record_to_scim(record)
  end
end

#update(&block) ⇒ Object

PATCH (update)

Calls #save! on the updated record if no block is given, else invokes the block, passing the updated record which the block must persist, with the same rules as for #create.



109
110
111
112
113
114
115
116
117
118
# File 'app/controllers/scimitar/active_record_backed_resources_controller.rb', line 109

def update(&block)
  super do |record_id, patch_hash|
    self.storage_class().transaction do
      record = self.find_record(record_id)
      record.from_scim_patch!(patch_hash: patch_hash)
      self.save!(record, &block)
      record_to_scim(record)
    end
  end
end