scimitar 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/scimitar/active_record_backed_resources_controller.rb +27 -7
- data/lib/scimitar/version.rb +2 -2
- data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
- data/spec/apps/dummy/app/models/mock_group.rb +1 -1
- data/spec/apps/dummy/app/models/mock_user.rb +3 -3
- data/spec/apps/dummy/config/routes.rb +3 -0
- data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +2 -2
- data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +8 -3
- data/spec/apps/dummy/db/schema.rb +9 -7
- data/spec/models/scimitar/lists/query_parser_spec.rb +8 -8
- data/spec/models/scimitar/resources/mixin_spec.rb +67 -39
- data/spec/models/scimitar/resources/user_spec.rb +2 -2
- data/spec/requests/active_record_backed_resources_controller_spec.rb +96 -48
- metadata +35 -37
- data/spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb +0 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: cd0efbdecece6297062b46cf46bdeaccd8330cd58fc94fb2bcb0de7c7bb90806
         | 
| 4 | 
            +
              data.tar.gz: 7f3528ee080f0f295d03c77fba1586484b5cadd6ef5e4de1fc00d7807ec7a0c1
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8044cc09d7b964401b09e6fe8ccfa272b6c67ab97687c79a151010a447109f9e671bb864094905b2495100591e2472f673ce2b977fc07f2a13213a8d4fbc75b1
         | 
| 7 | 
            +
              data.tar.gz: 51a5522fcf948d3b9f19c6bc5b28732f0fb4537034106d47dca83d7d043d5749d9adf1c31acf10fc7eb79a63739787a0ec42f0a261eb293072634aabca0ec92d
         | 
| @@ -21,6 +21,8 @@ module Scimitar | |
| 21 21 |  | 
| 22 22 | 
             
                rescue_from ActiveRecord::RecordNotFound, with: :handle_resource_not_found # See Scimitar::ApplicationController
         | 
| 23 23 |  | 
| 24 | 
            +
                before_action :obtain_id_column_name_from_attribute_map
         | 
| 25 | 
            +
             | 
| 24 26 | 
             
                # GET (list)
         | 
| 25 27 | 
             
                #
         | 
| 26 28 | 
             
                def index
         | 
| @@ -37,13 +39,13 @@ module Scimitar | |
| 37 39 | 
             
                  pagination_info = scim_pagination_info(query.count())
         | 
| 38 40 |  | 
| 39 41 | 
             
                  page_of_results = query
         | 
| 40 | 
            -
                    .order( | 
| 42 | 
            +
                    .order(@id_column => :asc)
         | 
| 41 43 | 
             
                    .offset(pagination_info.offset)
         | 
| 42 44 | 
             
                    .limit(pagination_info.limit)
         | 
| 43 45 | 
             
                    .to_a()
         | 
| 44 46 |  | 
| 45 47 | 
             
                  super(pagination_info, page_of_results) do | record |
         | 
| 46 | 
            -
                     | 
| 48 | 
            +
                    record_to_scim(record)
         | 
| 47 49 | 
             
                  end
         | 
| 48 50 | 
             
                end
         | 
| 49 51 |  | 
| @@ -52,7 +54,7 @@ module Scimitar | |
| 52 54 | 
             
                def show
         | 
| 53 55 | 
             
                  super do |record_id|
         | 
| 54 56 | 
             
                    record = self.find_record(record_id)
         | 
| 55 | 
            -
                    record | 
| 57 | 
            +
                    record_to_scim(record)
         | 
| 56 58 | 
             
                  end
         | 
| 57 59 | 
             
                end
         | 
| 58 60 |  | 
| @@ -64,7 +66,7 @@ module Scimitar | |
| 64 66 | 
             
                      record = self.storage_class().new
         | 
| 65 67 | 
             
                      record.from_scim!(scim_hash: scim_resource.as_json())
         | 
| 66 68 | 
             
                      self.save!(record)
         | 
| 67 | 
            -
                       | 
| 69 | 
            +
                      record_to_scim(record)
         | 
| 68 70 | 
             
                    end
         | 
| 69 71 | 
             
                  end
         | 
| 70 72 | 
             
                end
         | 
| @@ -77,7 +79,7 @@ module Scimitar | |
| 77 79 | 
             
                      record = self.find_record(record_id)
         | 
| 78 80 | 
             
                      record.from_scim!(scim_hash: scim_resource.as_json())
         | 
| 79 81 | 
             
                      self.save!(record)
         | 
| 80 | 
            -
                       | 
| 82 | 
            +
                      record_to_scim(record)
         | 
| 81 83 | 
             
                    end
         | 
| 82 84 | 
             
                  end
         | 
| 83 85 | 
             
                end
         | 
| @@ -90,7 +92,7 @@ module Scimitar | |
| 90 92 | 
             
                      record = self.find_record(record_id)
         | 
| 91 93 | 
             
                      record.from_scim_patch!(patch_hash: patch_hash)
         | 
| 92 94 | 
             
                      self.save!(record)
         | 
| 93 | 
            -
                       | 
| 95 | 
            +
                      record_to_scim(record)
         | 
| 94 96 | 
             
                    end
         | 
| 95 97 | 
             
                  end
         | 
| 96 98 | 
             
                end
         | 
| @@ -138,7 +140,14 @@ module Scimitar | |
| 138 140 | 
             
                  # +record_id+:: Record ID (SCIM schema 'id' value - "our" ID).
         | 
| 139 141 | 
             
                  #
         | 
| 140 142 | 
             
                  def find_record(record_id)
         | 
| 141 | 
            -
                    self.storage_scope(). | 
| 143 | 
            +
                    self.storage_scope().find_by!(@id_column => record_id)
         | 
| 144 | 
            +
                  end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  # DRY up controller actions - pass a record; returns the SCIM
         | 
| 147 | 
            +
                  # representation, with a "show" location specified via #url_for.
         | 
| 148 | 
            +
                  #
         | 
| 149 | 
            +
                  def record_to_scim(record)
         | 
| 150 | 
            +
                    record.to_scim(location: url_for(action: :show, id: record.send(@id_column)))
         | 
| 142 151 | 
             
                  end
         | 
| 143 152 |  | 
| 144 153 | 
             
                  # Save a record, dealing with validation exceptions by raising SCIM
         | 
| @@ -177,5 +186,16 @@ module Scimitar | |
| 177 186 | 
             
                    end
         | 
| 178 187 | 
             
                  end
         | 
| 179 188 |  | 
| 189 | 
            +
                  # Called via +before_action+ - stores in @id_column the name of whatever
         | 
| 190 | 
            +
                  # model column is used to store the record ID, via
         | 
| 191 | 
            +
                  # Scimitar::Resources::Mixin::scim_attributes_map.
         | 
| 192 | 
            +
                  #
         | 
| 193 | 
            +
                  # Default is <tt>:id</tt>.
         | 
| 194 | 
            +
                  #
         | 
| 195 | 
            +
                  def obtain_id_column_name_from_attribute_map
         | 
| 196 | 
            +
                    attrs      = storage_class().scim_attributes_map() || {}
         | 
| 197 | 
            +
                    @id_column = attrs[:id] || :id
         | 
| 198 | 
            +
                  end
         | 
| 199 | 
            +
             | 
| 180 200 | 
             
              end
         | 
| 181 201 | 
             
            end
         | 
    
        data/lib/scimitar/version.rb
    CHANGED
    
    | @@ -3,11 +3,11 @@ module Scimitar | |
| 3 3 | 
             
              # Gem version. If this changes, be sure to re-run "bundle install" or
         | 
| 4 4 | 
             
              # "bundle update".
         | 
| 5 5 | 
             
              #
         | 
| 6 | 
            -
              VERSION = '1. | 
| 6 | 
            +
              VERSION = '1.4.0'
         | 
| 7 7 |  | 
| 8 8 | 
             
              # Date for VERSION. If this changes, be sure to re-run "bundle install"
         | 
| 9 9 | 
             
              # or "bundle update".
         | 
| 10 10 | 
             
              #
         | 
| 11 | 
            -
              DATE = '2023-01- | 
| 11 | 
            +
              DATE = '2023-01-26'
         | 
| 12 12 |  | 
| 13 13 | 
             
            end
         | 
| @@ -5,7 +5,7 @@ class MockUser < ActiveRecord::Base | |
| 5 5 | 
             
              # ===========================================================================
         | 
| 6 6 |  | 
| 7 7 | 
             
              READWRITE_ATTRS = %w{
         | 
| 8 | 
            -
                 | 
| 8 | 
            +
                primary_key
         | 
| 9 9 | 
             
                scim_uid
         | 
| 10 10 | 
             
                username
         | 
| 11 11 | 
             
                first_name
         | 
| @@ -38,7 +38,7 @@ class MockUser < ActiveRecord::Base | |
| 38 38 |  | 
| 39 39 | 
             
              def self.scim_attributes_map
         | 
| 40 40 | 
             
                return {
         | 
| 41 | 
            -
                  id:         : | 
| 41 | 
            +
                  id:         :primary_key,
         | 
| 42 42 | 
             
                  externalId: :scim_uid,
         | 
| 43 43 | 
             
                  userName:   :username,
         | 
| 44 44 | 
             
                  name:       {
         | 
| @@ -92,7 +92,7 @@ class MockUser < ActiveRecord::Base | |
| 92 92 |  | 
| 93 93 | 
             
              def self.scim_queryable_attributes
         | 
| 94 94 | 
             
                return {
         | 
| 95 | 
            -
                  'id'                => { column: : | 
| 95 | 
            +
                  'id'                => { column: :primary_key },
         | 
| 96 96 | 
             
                  'externalId'        => { column: :scim_uid },
         | 
| 97 97 | 
             
                  'meta.lastModified' => { column: :updated_at },
         | 
| 98 98 | 
             
                  'name.givenName'    => { column: :first_name },
         | 
| @@ -13,6 +13,9 @@ Rails.application.routes.draw do | |
| 13 13 | 
             
              patch  'Users/:id', to: 'mock_users#update'
         | 
| 14 14 | 
             
              delete 'Users/:id', to: 'mock_users#destroy'
         | 
| 15 15 |  | 
| 16 | 
            +
              get    'Groups',     to: 'mock_groups#index'
         | 
| 17 | 
            +
              get    'Groups/:id', to: 'mock_groups#show'
         | 
| 18 | 
            +
             | 
| 16 19 | 
             
              # For testing blocks passed to ActiveRecordBackedResourcesController#destroy
         | 
| 17 20 | 
             
              #
         | 
| 18 21 | 
             
              delete 'CustomDestroyUsers/:id', to: 'custom_destroy_mock_users#destroy'
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            class CreateMockUsers < ActiveRecord::Migration[6.1]
         | 
| 2 2 | 
             
              def change
         | 
| 3 | 
            -
                create_table :mock_users do |t|
         | 
| 3 | 
            +
                create_table :mock_users, id: :uuid, primary_key: :primary_key do |t|
         | 
| 4 | 
            +
                  t.timestamps
         | 
| 4 5 |  | 
| 5 6 | 
             
                  t.text :scim_uid
         | 
| 6 7 | 
             
                  t.text :username
         | 
| @@ -9,7 +10,6 @@ class CreateMockUsers < ActiveRecord::Migration[6.1] | |
| 9 10 | 
             
                  t.text :work_email_address
         | 
| 10 11 | 
             
                  t.text :home_email_address
         | 
| 11 12 | 
             
                  t.text :work_phone_number
         | 
| 12 | 
            -
             | 
| 13 13 | 
             
                end
         | 
| 14 14 | 
             
              end
         | 
| 15 15 | 
             
            end
         | 
| @@ -1,8 +1,13 @@ | |
| 1 1 | 
             
            class CreateJoinTableMockGroupsMockUsers < ActiveRecord::Migration[6.1]
         | 
| 2 2 | 
             
              def change
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
                  t. | 
| 5 | 
            -
                  t.index  | 
| 3 | 
            +
                create_table :mock_groups_users, id: false do | t |
         | 
| 4 | 
            +
                  t.references :mock_group, foreign_key: true, type: :int8, index: true, null: false
         | 
| 5 | 
            +
                  t.references :mock_user,                     type: :uuid, index: true, null: false, primary_key: :primary_key
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  # The 'foreign_key:' option (used above) only works for 'id' column names
         | 
| 8 | 
            +
                  # but the test data has a column named 'primary_key' for 'mock_users'.
         | 
| 9 | 
            +
                  #
         | 
| 10 | 
            +
                  t.foreign_key :mock_users, primary_key: :primary_key
         | 
| 6 11 | 
             
                end
         | 
| 7 12 | 
             
              end
         | 
| 8 13 | 
             
            end
         | 
| @@ -10,7 +10,7 @@ | |
| 10 10 | 
             
            #
         | 
| 11 11 | 
             
            # It's strongly recommended that you check this file into your version control system.
         | 
| 12 12 |  | 
| 13 | 
            -
            ActiveRecord::Schema.define(version:  | 
| 13 | 
            +
            ActiveRecord::Schema.define(version: 2021_03_08_044214) do
         | 
| 14 14 |  | 
| 15 15 | 
             
              # These are extensions that must be enabled in order to support this database
         | 
| 16 16 | 
             
              enable_extension "plpgsql"
         | 
| @@ -24,12 +24,14 @@ ActiveRecord::Schema.define(version: 2023_01_09_012729) do | |
| 24 24 |  | 
| 25 25 | 
             
              create_table "mock_groups_users", id: false, force: :cascade do |t|
         | 
| 26 26 | 
             
                t.bigint "mock_group_id", null: false
         | 
| 27 | 
            -
                t. | 
| 28 | 
            -
                t.index ["mock_group_id" | 
| 29 | 
            -
                t.index ["mock_user_id" | 
| 27 | 
            +
                t.uuid "mock_user_id", null: false
         | 
| 28 | 
            +
                t.index ["mock_group_id"], name: "index_mock_groups_users_on_mock_group_id"
         | 
| 29 | 
            +
                t.index ["mock_user_id"], name: "index_mock_groups_users_on_mock_user_id"
         | 
| 30 30 | 
             
              end
         | 
| 31 31 |  | 
| 32 | 
            -
              create_table "mock_users", force: :cascade do |t|
         | 
| 32 | 
            +
              create_table "mock_users", primary_key: "primary_key", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
         | 
| 33 | 
            +
                t.datetime "created_at", precision: 6, null: false
         | 
| 34 | 
            +
                t.datetime "updated_at", precision: 6, null: false
         | 
| 33 35 | 
             
                t.text "scim_uid"
         | 
| 34 36 | 
             
                t.text "username"
         | 
| 35 37 | 
             
                t.text "first_name"
         | 
| @@ -37,8 +39,8 @@ ActiveRecord::Schema.define(version: 2023_01_09_012729) do | |
| 37 39 | 
             
                t.text "work_email_address"
         | 
| 38 40 | 
             
                t.text "home_email_address"
         | 
| 39 41 | 
             
                t.text "work_phone_number"
         | 
| 40 | 
            -
                t.datetime "created_at", precision: 6, null: false
         | 
| 41 | 
            -
                t.datetime "updated_at", precision: 6, null: false
         | 
| 42 42 | 
             
              end
         | 
| 43 43 |  | 
| 44 | 
            +
              add_foreign_key "mock_groups_users", "mock_groups"
         | 
| 45 | 
            +
              add_foreign_key "mock_groups_users", "mock_users", primary_key: "primary_key"
         | 
| 44 46 | 
             
            end
         | 
| @@ -405,19 +405,19 @@ RSpec.describe Scimitar::Lists::QueryParser do | |
| 405 405 | 
             
                  query = @instance.to_activerecord_query(MockUser.all)
         | 
| 406 406 |  | 
| 407 407 | 
             
                  expect(query.count).to eql(1)
         | 
| 408 | 
            -
                  expect(query.pluck(: | 
| 408 | 
            +
                  expect(query.pluck(:primary_key)).to eql([user_1.id])
         | 
| 409 409 |  | 
| 410 410 | 
             
                  @instance.parse('name.givenName sw J') # First name starts with 'J'
         | 
| 411 411 | 
             
                  query = @instance.to_activerecord_query(MockUser.all)
         | 
| 412 412 |  | 
| 413 413 | 
             
                  expect(query.count).to eql(2)
         | 
| 414 | 
            -
                  expect(query.pluck(: | 
| 414 | 
            +
                  expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key])
         | 
| 415 415 |  | 
| 416 416 | 
             
                  @instance.parse('name.familyName ew he') # Last name ends with 'he'
         | 
| 417 417 | 
             
                  query = @instance.to_activerecord_query(MockUser.all)
         | 
| 418 418 |  | 
| 419 419 | 
             
                  expect(query.count).to eql(1)
         | 
| 420 | 
            -
                  expect(query.pluck(: | 
| 420 | 
            +
                  expect(query.pluck(:primary_key)).to eql([user_2.primary_key])
         | 
| 421 421 |  | 
| 422 422 | 
             
                  # Test presence
         | 
| 423 423 |  | 
| @@ -425,7 +425,7 @@ RSpec.describe Scimitar::Lists::QueryParser do | |
| 425 425 | 
             
                  query = @instance.to_activerecord_query(MockUser.all)
         | 
| 426 426 |  | 
| 427 427 | 
             
                  expect(query.count).to eql(2)
         | 
| 428 | 
            -
                  expect(query.pluck(: | 
| 428 | 
            +
                  expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key])
         | 
| 429 429 |  | 
| 430 430 | 
             
                  # Test a simple not-equals, but use a custom starting scope. Note that
         | 
| 431 431 | 
             
                  # the query would find "user_3" *except* there is no first name defined
         | 
| @@ -435,7 +435,7 @@ RSpec.describe Scimitar::Lists::QueryParser do | |
| 435 435 | 
             
                  query = @instance.to_activerecord_query(MockUser.where.not('first_name' => 'John'))
         | 
| 436 436 |  | 
| 437 437 | 
             
                  expect(query.count).to eql(1)
         | 
| 438 | 
            -
                  expect(query.pluck(: | 
| 438 | 
            +
                  expect(query.pluck(:primary_key)).to match_array([user_1.primary_key])
         | 
| 439 439 | 
             
                end
         | 
| 440 440 |  | 
| 441 441 | 
             
                context 'when mapped to multiple columns' do
         | 
| @@ -499,7 +499,7 @@ RSpec.describe Scimitar::Lists::QueryParser do | |
| 499 499 | 
             
                      query = @instance.to_activerecord_query(MockUser.all)
         | 
| 500 500 |  | 
| 501 501 | 
             
                      expect(query.count).to eql(1)
         | 
| 502 | 
            -
                      expect(query.pluck(: | 
| 502 | 
            +
                      expect(query.pluck(:primary_key)).to match_array([user_2.primary_key])
         | 
| 503 503 | 
             
                    end
         | 
| 504 504 | 
             
                  end # "context 'simple AND' do"
         | 
| 505 505 |  | 
| @@ -520,7 +520,7 @@ RSpec.describe Scimitar::Lists::QueryParser do | |
| 520 520 | 
             
                      query = @instance.to_activerecord_query(MockUser.all)
         | 
| 521 521 |  | 
| 522 522 | 
             
                      expect(query.count).to eql(2)
         | 
| 523 | 
            -
                      expect(query.pluck(: | 
| 523 | 
            +
                      expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key])
         | 
| 524 524 | 
             
                    end
         | 
| 525 525 | 
             
                  end # "context 'simple OR' do"
         | 
| 526 526 |  | 
| @@ -546,7 +546,7 @@ RSpec.describe Scimitar::Lists::QueryParser do | |
| 546 546 | 
             
                      query = @instance.to_activerecord_query(MockUser.all)
         | 
| 547 547 |  | 
| 548 548 | 
             
                      expect(query.count).to eql(3)
         | 
| 549 | 
            -
                      expect(query.pluck(: | 
| 549 | 
            +
                      expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key, user_3.primary_key])
         | 
| 550 550 | 
             
                    end
         | 
| 551 551 | 
             
                  end # "context 'combined AND and OR' do"
         | 
| 552 552 |  | 
| @@ -159,41 +159,67 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 159 159 | 
             
                # =========================================================================
         | 
| 160 160 |  | 
| 161 161 | 
             
                context '#to_scim' do
         | 
| 162 | 
            -
                   | 
| 163 | 
            -
                    instance | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
                       | 
| 186 | 
            -
             | 
| 187 | 
            -
                       | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 162 | 
            +
                  context 'with a UUID, renamed primary key column' do
         | 
| 163 | 
            +
                    it 'compiles instance attribute values into a SCIM representation' do
         | 
| 164 | 
            +
                      uuid                        = SecureRandom.uuid
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                      instance                    = MockUser.new
         | 
| 167 | 
            +
                      instance.primary_key        = uuid
         | 
| 168 | 
            +
                      instance.scim_uid           = 'AA02984'
         | 
| 169 | 
            +
                      instance.username           = 'foo'
         | 
| 170 | 
            +
                      instance.first_name         = 'Foo'
         | 
| 171 | 
            +
                      instance.last_name          = 'Bar'
         | 
| 172 | 
            +
                      instance.work_email_address = 'foo.bar@test.com'
         | 
| 173 | 
            +
                      instance.home_email_address = nil
         | 
| 174 | 
            +
                      instance.work_phone_number  = '+642201234567'
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                      g1 = MockGroup.create!(display_name: 'Group 1')
         | 
| 177 | 
            +
                      g2 = MockGroup.create!(display_name: 'Group 2')
         | 
| 178 | 
            +
                      g3 = MockGroup.create!(display_name: 'Group 3')
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                      g1.mock_users << instance
         | 
| 181 | 
            +
                      g3.mock_users << instance
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                      scim = instance.to_scim(location: "https://test.com/mock_users/#{uuid}")
         | 
| 184 | 
            +
                      json = scim.to_json()
         | 
| 185 | 
            +
                      hash = JSON.parse(json)
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                      expect(hash).to eql({
         | 
| 188 | 
            +
                        'userName'    => 'foo',
         | 
| 189 | 
            +
                        'name'        => {'givenName'=>'Foo', 'familyName'=>'Bar'},
         | 
| 190 | 
            +
                        'active'      => true,
         | 
| 191 | 
            +
                        'emails'      => [{'type'=>'work', 'primary'=>true, 'value'=>'foo.bar@test.com'}, {"primary"=>false, "type"=>"home", "value"=>nil}],
         | 
| 192 | 
            +
                        'phoneNumbers'=> [{'type'=>'work', 'primary'=>false, 'value'=>'+642201234567'}],
         | 
| 193 | 
            +
                        'id'          => uuid,
         | 
| 194 | 
            +
                        'externalId'  => 'AA02984',
         | 
| 195 | 
            +
                        'groups'      => [{'display'=>g1.display_name, 'value'=>g1.id.to_s}, {'display'=>g3.display_name, 'value'=>g3.id.to_s}],
         | 
| 196 | 
            +
                        'meta'        => {'location'=>"https://test.com/mock_users/#{uuid}", 'resourceType'=>'User'},
         | 
| 197 | 
            +
                        'schemas'     => ['urn:ietf:params:scim:schemas:core:2.0:User']
         | 
| 198 | 
            +
                      })
         | 
| 199 | 
            +
                    end
         | 
| 200 | 
            +
                  end # "context 'with a UUID, renamed primary key column' do"
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                  context 'with an integer, conventionally named primary key column' do
         | 
| 203 | 
            +
                    it 'compiles instance attribute values into a SCIM representation' do
         | 
| 204 | 
            +
                      instance              = MockGroup.new
         | 
| 205 | 
            +
                      instance.id           = 42
         | 
| 206 | 
            +
                      instance.scim_uid     = 'GG02984'
         | 
| 207 | 
            +
                      instance.display_name = 'Some group'
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                      scim = instance.to_scim(location: 'https://test.com/mock_groups/42')
         | 
| 210 | 
            +
                      json = scim.to_json()
         | 
| 211 | 
            +
                      hash = JSON.parse(json)
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                      expect(hash).to eql({
         | 
| 214 | 
            +
                        'displayName' => 'Some group',
         | 
| 215 | 
            +
                        'id'          => '42', # Note, String
         | 
| 216 | 
            +
                        'externalId'  => 'GG02984',
         | 
| 217 | 
            +
                        'members'     => [],
         | 
| 218 | 
            +
                        'meta'        => {'location'=>'https://test.com/mock_groups/42', 'resourceType'=>'Group'},
         | 
| 219 | 
            +
                        'schemas'     => ['urn:ietf:params:scim:schemas:core:2.0:Group']
         | 
| 220 | 
            +
                      })
         | 
| 221 | 
            +
                    end
         | 
| 222 | 
            +
                  end # "context 'with an integer, conventionally named primary key column' do"
         | 
| 197 223 |  | 
| 198 224 | 
             
                  context 'with optional timestamps' do
         | 
| 199 225 | 
             
                    context 'creation only' do
         | 
| @@ -405,8 +431,8 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 405 431 | 
             
                          'displayName' => 'Foo Group',
         | 
| 406 432 | 
             
                          'members'     => [
         | 
| 407 433 | 
             
                            {'type' => 'Group', 'value' => g1.id.to_s},
         | 
| 408 | 
            -
                            {'type' => 'User',  'value' => u1. | 
| 409 | 
            -
                            {'type' => 'User',  'value' => u3. | 
| 434 | 
            +
                            {'type' => 'User',  'value' => u1.primary_key.to_s},
         | 
| 435 | 
            +
                            {'type' => 'User',  'value' => u3.primary_key.to_s}
         | 
| 410 436 | 
             
                          ],
         | 
| 411 437 | 
             
                          'externalId'  => 'GG01536',
         | 
| 412 438 | 
             
                          'meta'        => {'location'=>'https://test.com/mock_groups/1', 'resourceType'=>'Group'},
         | 
| @@ -453,8 +479,10 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 453 479 | 
             
                  end # "context 'using upper case' do"
         | 
| 454 480 |  | 
| 455 481 | 
             
                  it 'clears things not present in input' do
         | 
| 482 | 
            +
                    uuid                        = SecureRandom.uuid
         | 
| 483 | 
            +
             | 
| 456 484 | 
             
                    instance                    = MockUser.new
         | 
| 457 | 
            -
                    instance. | 
| 485 | 
            +
                    instance.primary_key        = uuid
         | 
| 458 486 | 
             
                    instance.scim_uid           = 'AA02984'
         | 
| 459 487 | 
             
                    instance.username           = 'foo'
         | 
| 460 488 | 
             
                    instance.first_name         = 'Foo'
         | 
| @@ -465,7 +493,7 @@ RSpec.describe Scimitar::Resources::Mixin do | |
| 465 493 |  | 
| 466 494 | 
             
                    instance.from_scim!(scim_hash: {})
         | 
| 467 495 |  | 
| 468 | 
            -
                    expect(instance. | 
| 496 | 
            +
                    expect(instance.primary_key       ).to eql(uuid)
         | 
| 469 497 | 
             
                    expect(instance.scim_uid          ).to be_nil
         | 
| 470 498 | 
             
                    expect(instance.username          ).to be_nil
         | 
| 471 499 | 
             
                    expect(instance.first_name        ).to be_nil
         | 
| @@ -42,13 +42,13 @@ RSpec.describe Scimitar::Resources::User do | |
| 42 42 | 
             
                let(:user) { described_class.new }
         | 
| 43 43 |  | 
| 44 44 | 
             
                it 'adds the error when the value is a string' do
         | 
| 45 | 
            -
                  user.add_errors_from_hash(key: 'some error')
         | 
| 45 | 
            +
                  user.add_errors_from_hash({key: 'some error'})
         | 
| 46 46 | 
             
                  expect(user.errors.messages.to_h).to eql({key: ['some error']})
         | 
| 47 47 | 
             
                  expect(user.errors.full_messages).to eql(['Key some error'])
         | 
| 48 48 | 
             
                end
         | 
| 49 49 |  | 
| 50 50 | 
             
                it 'adds the error when the value is an array' do
         | 
| 51 | 
            -
                  user.add_errors_from_hash(key: ['error1', 'error2'])
         | 
| 51 | 
            +
                  user.add_errors_from_hash({key: ['error1', 'error2']})
         | 
| 52 52 | 
             
                  expect(user.errors.messages.to_h).to eql({key: ['error1', 'error2']})
         | 
| 53 53 | 
             
                  expect(user.errors.full_messages).to eql(['Key error1', 'Key error2'])
         | 
| 54 54 | 
             
                end
         | 
| @@ -7,9 +7,21 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 7 7 |  | 
| 8 8 | 
             
                lmt = Time.parse("2023-01-09 14:25:00 +1300")
         | 
| 9 9 |  | 
| 10 | 
            -
                 | 
| 11 | 
            -
                 | 
| 12 | 
            -
                 | 
| 10 | 
            +
                # If a sort order is unspecified, the controller defaults to ID ascending.
         | 
| 11 | 
            +
                # With UUID based IDs, testing life is made easier by ensuring that the
         | 
| 12 | 
            +
                # creation order matches an ascending UUID sort order (which is what would
         | 
| 13 | 
            +
                # happen if we were using integer primary keys).
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                lmt = Time.parse("2023-01-09 14:25:00 +1300")
         | 
| 16 | 
            +
                ids = 3.times.map { SecureRandom.uuid }.sort()
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                @u1 = MockUser.create(primary_key: ids.shift(), username: '1', first_name: 'Foo', last_name: 'Ark', home_email_address: 'home_1@test.com', scim_uid: '001', created_at: lmt, updated_at: lmt + 1)
         | 
| 19 | 
            +
                @u2 = MockUser.create(primary_key: ids.shift(), username: '2', first_name: 'Foo', last_name: 'Bar', home_email_address: 'home_2@test.com', scim_uid: '002', created_at: lmt, updated_at: lmt + 2)
         | 
| 20 | 
            +
                @u3 = MockUser.create(primary_key: ids.shift(), username: '3', first_name: 'Foo',                   home_email_address: 'home_3@test.com', scim_uid: '003', created_at: lmt, updated_at: lmt + 3)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                @g1 = MockGroup.create!(display_name: 'Group 1')
         | 
| 23 | 
            +
                @g2 = MockGroup.create!(display_name: 'Group 2')
         | 
| 24 | 
            +
                @g3 = MockGroup.create!(display_name: 'Group 3')
         | 
| 13 25 | 
             
              end
         | 
| 14 26 |  | 
| 15 27 | 
             
              # ===========================================================================
         | 
| @@ -32,21 +44,41 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 32 44 | 
             
                end # "context 'with no items' do"
         | 
| 33 45 |  | 
| 34 46 | 
             
                context 'with items' do
         | 
| 35 | 
            -
                   | 
| 36 | 
            -
                     | 
| 47 | 
            +
                  context 'with a UUID, renamed primary key column' do
         | 
| 48 | 
            +
                    it 'returns all items' do
         | 
| 49 | 
            +
                      get '/Users', params: { format: :scim }
         | 
| 37 50 |  | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 51 | 
            +
                      expect(response.status).to eql(200)
         | 
| 52 | 
            +
                      result = JSON.parse(response.body)
         | 
| 40 53 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 54 | 
            +
                      expect(result['totalResults']).to eql(3)
         | 
| 55 | 
            +
                      expect(result['Resources'].size).to eql(3)
         | 
| 43 56 |  | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 57 | 
            +
                      ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 58 | 
            +
                      expect(ids).to match_array([@u1.primary_key.to_s, @u2.primary_key.to_s, @u3.primary_key.to_s])
         | 
| 46 59 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 60 | 
            +
                      usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 61 | 
            +
                      expect(usernames).to match_array(['1', '2', '3'])
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end # "context 'with a UUID, renamed primary key column' do"
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  context 'with an integer, conventionally named primary key column' do
         | 
| 66 | 
            +
                    it 'returns all items' do
         | 
| 67 | 
            +
                      get '/Groups', params: { format: :scim }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                      expect(response.status).to eql(200)
         | 
| 70 | 
            +
                      result = JSON.parse(response.body)
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                      expect(result['totalResults']).to eql(3)
         | 
| 73 | 
            +
                      expect(result['Resources'].size).to eql(3)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                      ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 76 | 
            +
                      expect(ids).to match_array([@g1.id.to_s, @g2.id.to_s, @g3.id.to_s])
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                      usernames = result['Resources'].map { |resource| resource['displayName'] }
         | 
| 79 | 
            +
                      expect(usernames).to match_array(['Group 1', 'Group 2', 'Group 3'])
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end # "context 'with an integer, conventionally named primary key column' do"
         | 
| 50 82 |  | 
| 51 83 | 
             
                  it 'applies a filter, with case-insensitive value comparison' do
         | 
| 52 84 | 
             
                    get '/Users', params: {
         | 
| @@ -61,7 +93,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 61 93 | 
             
                    expect(result['Resources'].size).to eql(1)
         | 
| 62 94 |  | 
| 63 95 | 
             
                    ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 64 | 
            -
                    expect(ids).to match_array([@u2. | 
| 96 | 
            +
                    expect(ids).to match_array([@u2.primary_key.to_s])
         | 
| 65 97 |  | 
| 66 98 | 
             
                    usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 67 99 | 
             
                    expect(usernames).to match_array(['2'])
         | 
| @@ -80,7 +112,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 80 112 | 
             
                    expect(result['Resources'].size).to eql(1)
         | 
| 81 113 |  | 
| 82 114 | 
             
                    ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 83 | 
            -
                    expect(ids).to match_array([@u2. | 
| 115 | 
            +
                    expect(ids).to match_array([@u2.primary_key.to_s])
         | 
| 84 116 |  | 
| 85 117 | 
             
                    usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 86 118 | 
             
                    expect(usernames).to match_array(['2'])
         | 
| @@ -93,7 +125,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 93 125 | 
             
                    it 'applies a filter on primary keys, using direct comparison (rather than e.g. case-insensitive operators)' do
         | 
| 94 126 | 
             
                      get '/Users', params: {
         | 
| 95 127 | 
             
                        format: :scim,
         | 
| 96 | 
            -
                        filter: "id eq \"#{@u3. | 
| 128 | 
            +
                        filter: "id eq \"#{@u3.primary_key}\""
         | 
| 97 129 | 
             
                      }
         | 
| 98 130 |  | 
| 99 131 | 
             
                      expect(response.status).to eql(200)
         | 
| @@ -103,7 +135,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 103 135 | 
             
                      expect(result['Resources'].size).to eql(1)
         | 
| 104 136 |  | 
| 105 137 | 
             
                      ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 106 | 
            -
                      expect(ids).to match_array([@u3. | 
| 138 | 
            +
                      expect(ids).to match_array([@u3.primary_key.to_s])
         | 
| 107 139 |  | 
| 108 140 | 
             
                      usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 109 141 | 
             
                      expect(usernames).to match_array(['3'])
         | 
| @@ -122,7 +154,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 122 154 | 
             
                      expect(result['Resources'].size).to eql(1)
         | 
| 123 155 |  | 
| 124 156 | 
             
                      ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 125 | 
            -
                      expect(ids).to match_array([@u2. | 
| 157 | 
            +
                      expect(ids).to match_array([@u2.primary_key.to_s])
         | 
| 126 158 |  | 
| 127 159 | 
             
                      usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 128 160 | 
             
                      expect(usernames).to match_array(['2'])
         | 
| @@ -141,7 +173,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 141 173 | 
             
                      expect(result['Resources'].size).to eql(1)
         | 
| 142 174 |  | 
| 143 175 | 
             
                      ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 144 | 
            -
                      expect(ids).to match_array([@u3. | 
| 176 | 
            +
                      expect(ids).to match_array([@u3.primary_key.to_s])
         | 
| 145 177 |  | 
| 146 178 | 
             
                      usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 147 179 | 
             
                      expect(usernames).to match_array(['3'])
         | 
| @@ -161,7 +193,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 161 193 | 
             
                    expect(result['Resources'].size).to eql(2)
         | 
| 162 194 |  | 
| 163 195 | 
             
                    ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 164 | 
            -
                    expect(ids).to match_array([@u1. | 
| 196 | 
            +
                    expect(ids).to match_array([@u1.primary_key.to_s, @u2.primary_key.to_s])
         | 
| 165 197 |  | 
| 166 198 | 
             
                    usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 167 199 | 
             
                    expect(usernames).to match_array(['1', '2'])
         | 
| @@ -180,7 +212,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 180 212 | 
             
                    expect(result['Resources'].size).to eql(2)
         | 
| 181 213 |  | 
| 182 214 | 
             
                    ids = result['Resources'].map { |resource| resource['id'] }
         | 
| 183 | 
            -
                    expect(ids).to match_array([@u2. | 
| 215 | 
            +
                    expect(ids).to match_array([@u2.primary_key.to_s, @u3.primary_key.to_s])
         | 
| 184 216 |  | 
| 185 217 | 
             
                    usernames = result['Resources'].map { |resource| resource['userName'] }
         | 
| 186 218 | 
             
                    expect(usernames).to match_array(['2', '3'])
         | 
| @@ -204,18 +236,34 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 204 236 | 
             
              # ===========================================================================
         | 
| 205 237 |  | 
| 206 238 | 
             
              context '#show' do
         | 
| 207 | 
            -
                 | 
| 208 | 
            -
                   | 
| 209 | 
            -
             | 
| 239 | 
            +
                context 'with a UUID, renamed primary key column' do
         | 
| 240 | 
            +
                  it 'shows an item' do
         | 
| 241 | 
            +
                    expect_any_instance_of(MockUsersController).to receive(:show).once.and_call_original
         | 
| 242 | 
            +
                    get "/Users/#{@u2.primary_key}", params: { format: :scim }
         | 
| 210 243 |  | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 244 | 
            +
                    expect(response.status).to eql(200)
         | 
| 245 | 
            +
                    result = JSON.parse(response.body)
         | 
| 213 246 |  | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 247 | 
            +
                    expect(result['id']).to eql(@u2.primary_key.to_s)
         | 
| 248 | 
            +
                    expect(result['userName']).to eql('2')
         | 
| 249 | 
            +
                    expect(result['name']['familyName']).to eql('Bar')
         | 
| 250 | 
            +
                    expect(result['meta']['resourceType']).to eql('User')
         | 
| 251 | 
            +
                  end
         | 
| 252 | 
            +
                end # "context 'with a UUID, renamed primary key column' do"
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                context 'with an integer, conventionally named primary key column' do
         | 
| 255 | 
            +
                  it 'shows an item' do
         | 
| 256 | 
            +
                    expect_any_instance_of(MockGroupsController).to receive(:show).once.and_call_original
         | 
| 257 | 
            +
                    get "/Groups/#{@g2.id}", params: { format: :scim }
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                    expect(response.status).to eql(200)
         | 
| 260 | 
            +
                    result = JSON.parse(response.body)
         | 
| 261 | 
            +
             | 
| 262 | 
            +
                    expect(result['id']).to eql(@g2.id.to_s) # Note - ID was converted String; not Integer
         | 
| 263 | 
            +
                    expect(result['displayName']).to eql('Group 2')
         | 
| 264 | 
            +
                    expect(result['meta']['resourceType']).to eql('Group')
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
                end # "context 'with an integer, conventionally named primary key column' do"
         | 
| 219 267 |  | 
| 220 268 | 
             
                it 'renders 404' do
         | 
| 221 269 | 
             
                  get '/Users/xyz', params: { format: :scim }
         | 
| @@ -248,7 +296,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 248 296 | 
             
                      expect(response.status).to eql(201)
         | 
| 249 297 | 
             
                      result = JSON.parse(response.body)
         | 
| 250 298 |  | 
| 251 | 
            -
                      expect(result['id']).to eql(new_mock. | 
| 299 | 
            +
                      expect(result['id']).to eql(new_mock.primary_key.to_s)
         | 
| 252 300 | 
             
                      expect(result['meta']['resourceType']).to eql('User')
         | 
| 253 301 | 
             
                      expect(new_mock.username).to eql('4')
         | 
| 254 302 | 
             
                    end
         | 
| @@ -289,7 +337,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 289 337 | 
             
                      expect(response.status).to eql(201)
         | 
| 290 338 | 
             
                      result = JSON.parse(response.body)
         | 
| 291 339 |  | 
| 292 | 
            -
                      expect(result['id']).to eql(new_mock. | 
| 340 | 
            +
                      expect(result['id']).to eql(new_mock.primary_key.to_s)
         | 
| 293 341 | 
             
                      expect(result['meta']['resourceType']).to eql('User')
         | 
| 294 342 | 
             
                      expect(new_mock.username).to eql('4')
         | 
| 295 343 | 
             
                      expect(new_mock.first_name).to eql('Given')
         | 
| @@ -363,13 +411,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 363 411 |  | 
| 364 412 | 
             
                    expect_any_instance_of(MockUsersController).to receive(:replace).once.and_call_original
         | 
| 365 413 | 
             
                    expect {
         | 
| 366 | 
            -
                      put "/Users/#{@u2. | 
| 414 | 
            +
                      put "/Users/#{@u2.primary_key}", params: attributes.merge(format: :scim)
         | 
| 367 415 | 
             
                    }.to_not change { MockUser.count }
         | 
| 368 416 |  | 
| 369 417 | 
             
                    expect(response.status).to eql(200)
         | 
| 370 418 | 
             
                    result = JSON.parse(response.body)
         | 
| 371 419 |  | 
| 372 | 
            -
                    expect(result['id']).to eql(@u2. | 
| 420 | 
            +
                    expect(result['id']).to eql(@u2.primary_key.to_s)
         | 
| 373 421 | 
             
                    expect(result['meta']['resourceType']).to eql('User')
         | 
| 374 422 |  | 
| 375 423 | 
             
                    @u2.reload
         | 
| @@ -391,7 +439,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 391 439 |  | 
| 392 440 | 
             
                it 'notes schema validation failures' do
         | 
| 393 441 | 
             
                  expect {
         | 
| 394 | 
            -
                    put "/Users/#{@u2. | 
| 442 | 
            +
                    put "/Users/#{@u2.primary_key}", params: {
         | 
| 395 443 | 
             
                      format: :scim
         | 
| 396 444 | 
             
                      # userName parameter is required by schema, but missing
         | 
| 397 445 | 
             
                    }
         | 
| @@ -470,13 +518,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 470 518 |  | 
| 471 519 | 
             
                    expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
         | 
| 472 520 | 
             
                    expect {
         | 
| 473 | 
            -
                      patch "/Users/#{@u2. | 
| 521 | 
            +
                      patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
         | 
| 474 522 | 
             
                    }.to_not change { MockUser.count }
         | 
| 475 523 |  | 
| 476 524 | 
             
                    expect(response.status).to eql(200)
         | 
| 477 525 | 
             
                    result = JSON.parse(response.body)
         | 
| 478 526 |  | 
| 479 | 
            -
                    expect(result['id']).to eql(@u2. | 
| 527 | 
            +
                    expect(result['id']).to eql(@u2.primary_key.to_s)
         | 
| 480 528 | 
             
                    expect(result['meta']['resourceType']).to eql('User')
         | 
| 481 529 |  | 
| 482 530 | 
             
                    @u2.reload
         | 
| @@ -507,13 +555,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 507 555 |  | 
| 508 556 | 
             
                      expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
         | 
| 509 557 | 
             
                      expect {
         | 
| 510 | 
            -
                        patch "/Users/#{@u2. | 
| 558 | 
            +
                        patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
         | 
| 511 559 | 
             
                      }.to_not change { MockUser.count }
         | 
| 512 560 |  | 
| 513 561 | 
             
                      expect(response.status).to eql(200)
         | 
| 514 562 | 
             
                      result = JSON.parse(response.body)
         | 
| 515 563 |  | 
| 516 | 
            -
                      expect(result['id']).to eql(@u2. | 
| 564 | 
            +
                      expect(result['id']).to eql(@u2.primary_key.to_s)
         | 
| 517 565 | 
             
                      expect(result['meta']['resourceType']).to eql('User')
         | 
| 518 566 |  | 
| 519 567 | 
             
                      @u2.reload
         | 
| @@ -539,13 +587,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 539 587 |  | 
| 540 588 | 
             
                      expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
         | 
| 541 589 | 
             
                      expect {
         | 
| 542 | 
            -
                        patch "/Users/#{@u2. | 
| 590 | 
            +
                        patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
         | 
| 543 591 | 
             
                      }.to_not change { MockUser.count }
         | 
| 544 592 |  | 
| 545 593 | 
             
                      expect(response.status).to eql(200)
         | 
| 546 594 | 
             
                      result = JSON.parse(response.body)
         | 
| 547 595 |  | 
| 548 | 
            -
                      expect(result['id']).to eql(@u2. | 
| 596 | 
            +
                      expect(result['id']).to eql(@u2.primary_key.to_s)
         | 
| 549 597 | 
             
                      expect(result['meta']['resourceType']).to eql('User')
         | 
| 550 598 |  | 
| 551 599 | 
             
                      @u2.reload
         | 
| @@ -571,13 +619,13 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 571 619 |  | 
| 572 620 | 
             
                      expect_any_instance_of(MockUsersController).to receive(:update).once.and_call_original
         | 
| 573 621 | 
             
                      expect {
         | 
| 574 | 
            -
                        patch "/Users/#{@u2. | 
| 622 | 
            +
                        patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
         | 
| 575 623 | 
             
                      }.to_not change { MockUser.count }
         | 
| 576 624 |  | 
| 577 625 | 
             
                      expect(response.status).to eql(200)
         | 
| 578 626 | 
             
                      result = JSON.parse(response.body)
         | 
| 579 627 |  | 
| 580 | 
            -
                      expect(result['id']).to eql(@u2. | 
| 628 | 
            +
                      expect(result['id']).to eql(@u2.primary_key.to_s)
         | 
| 581 629 | 
             
                      expect(result['meta']['resourceType']).to eql('User')
         | 
| 582 630 |  | 
| 583 631 | 
             
                      @u2.reload
         | 
| @@ -601,7 +649,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 601 649 |  | 
| 602 650 | 
             
                it 'notes Rails validation failures' do
         | 
| 603 651 | 
             
                  expect {
         | 
| 604 | 
            -
                    patch "/Users/#{@u2. | 
| 652 | 
            +
                    patch "/Users/#{@u2.primary_key}", params: {
         | 
| 605 653 | 
             
                      format: :scim,
         | 
| 606 654 | 
             
                      Operations: [
         | 
| 607 655 | 
             
                        {
         | 
| @@ -654,7 +702,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 654 702 | 
             
                  expect_any_instance_of(MockUsersController).to receive(:destroy).once.and_call_original
         | 
| 655 703 | 
             
                  expect_any_instance_of(MockUser).to receive(:destroy!).once.and_call_original
         | 
| 656 704 | 
             
                  expect {
         | 
| 657 | 
            -
                    delete "/Users/#{@u2. | 
| 705 | 
            +
                    delete "/Users/#{@u2.primary_key}", params: { format: :scim }
         | 
| 658 706 | 
             
                  }.to change { MockUser.count }.by(-1)
         | 
| 659 707 |  | 
| 660 708 | 
             
                  expect(response.status).to eql(204)
         | 
| @@ -666,7 +714,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do | |
| 666 714 | 
             
                  expect_any_instance_of(MockUser).to_not receive(:destroy!)
         | 
| 667 715 |  | 
| 668 716 | 
             
                  expect {
         | 
| 669 | 
            -
                    delete "/CustomDestroyUsers/#{@u2. | 
| 717 | 
            +
                    delete "/CustomDestroyUsers/#{@u2.primary_key}", params: { format: :scim }
         | 
| 670 718 | 
             
                  }.to_not change { MockUser.count }
         | 
| 671 719 |  | 
| 672 720 | 
             
                  expect(response.status).to eql(204)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: scimitar
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.4.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - RIPA Global
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire:
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2023-01- | 
| 12 | 
            +
            date: 2023-01-26 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: rails
         | 
| @@ -211,7 +211,6 @@ files: | |
| 211 211 | 
             
            - spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb
         | 
| 212 212 | 
             
            - spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb
         | 
| 213 213 | 
             
            - spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb
         | 
| 214 | 
            -
            - spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb
         | 
| 215 214 | 
             
            - spec/apps/dummy/db/schema.rb
         | 
| 216 215 | 
             
            - spec/controllers/scimitar/application_controller_spec.rb
         | 
| 217 216 | 
             
            - spec/controllers/scimitar/resource_types_controller_spec.rb
         | 
| @@ -261,52 +260,51 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 261 260 | 
             
                - !ruby/object:Gem::Version
         | 
| 262 261 | 
             
                  version: '0'
         | 
| 263 262 | 
             
            requirements: []
         | 
| 264 | 
            -
            rubygems_version: 3. | 
| 263 | 
            +
            rubygems_version: 3.4.4
         | 
| 265 264 | 
             
            signing_key:
         | 
| 266 265 | 
             
            specification_version: 4
         | 
| 267 266 | 
             
            summary: SCIM v2 for Rails
         | 
| 268 267 | 
             
            test_files:
         | 
| 269 | 
            -
            - spec/ | 
| 270 | 
            -
            - spec/ | 
| 268 | 
            +
            - spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb
         | 
| 269 | 
            +
            - spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb
         | 
| 270 | 
            +
            - spec/apps/dummy/app/controllers/mock_groups_controller.rb
         | 
| 271 | 
            +
            - spec/apps/dummy/app/controllers/mock_users_controller.rb
         | 
| 272 | 
            +
            - spec/apps/dummy/app/models/mock_group.rb
         | 
| 273 | 
            +
            - spec/apps/dummy/app/models/mock_user.rb
         | 
| 274 | 
            +
            - spec/apps/dummy/config/application.rb
         | 
| 275 | 
            +
            - spec/apps/dummy/config/boot.rb
         | 
| 276 | 
            +
            - spec/apps/dummy/config/environment.rb
         | 
| 277 | 
            +
            - spec/apps/dummy/config/environments/test.rb
         | 
| 278 | 
            +
            - spec/apps/dummy/config/initializers/cookies_serializer.rb
         | 
| 279 | 
            +
            - spec/apps/dummy/config/initializers/scimitar.rb
         | 
| 280 | 
            +
            - spec/apps/dummy/config/initializers/session_store.rb
         | 
| 281 | 
            +
            - spec/apps/dummy/config/routes.rb
         | 
| 282 | 
            +
            - spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb
         | 
| 283 | 
            +
            - spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb
         | 
| 284 | 
            +
            - spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb
         | 
| 285 | 
            +
            - spec/apps/dummy/db/schema.rb
         | 
| 286 | 
            +
            - spec/controllers/scimitar/application_controller_spec.rb
         | 
| 287 | 
            +
            - spec/controllers/scimitar/resource_types_controller_spec.rb
         | 
| 288 | 
            +
            - spec/controllers/scimitar/resources_controller_spec.rb
         | 
| 289 | 
            +
            - spec/controllers/scimitar/schemas_controller_spec.rb
         | 
| 290 | 
            +
            - spec/controllers/scimitar/service_provider_configurations_controller_spec.rb
         | 
| 291 | 
            +
            - spec/models/scimitar/complex_types/address_spec.rb
         | 
| 292 | 
            +
            - spec/models/scimitar/complex_types/email_spec.rb
         | 
| 271 293 | 
             
            - spec/models/scimitar/lists/count_spec.rb
         | 
| 294 | 
            +
            - spec/models/scimitar/lists/query_parser_spec.rb
         | 
| 295 | 
            +
            - spec/models/scimitar/resource_type_spec.rb
         | 
| 296 | 
            +
            - spec/models/scimitar/resources/base_spec.rb
         | 
| 272 297 | 
             
            - spec/models/scimitar/resources/base_validation_spec.rb
         | 
| 273 298 | 
             
            - spec/models/scimitar/resources/mixin_spec.rb
         | 
| 274 299 | 
             
            - spec/models/scimitar/resources/user_spec.rb
         | 
| 275 | 
            -
            - spec/models/scimitar/resources/base_spec.rb
         | 
| 276 300 | 
             
            - spec/models/scimitar/schema/attribute_spec.rb
         | 
| 301 | 
            +
            - spec/models/scimitar/schema/base_spec.rb
         | 
| 277 302 | 
             
            - spec/models/scimitar/schema/group_spec.rb
         | 
| 278 303 | 
             
            - spec/models/scimitar/schema/user_spec.rb
         | 
| 279 | 
            -
            - spec/models/scimitar/schema/base_spec.rb
         | 
| 280 | 
            -
            - spec/models/scimitar/resource_type_spec.rb
         | 
| 281 | 
            -
            - spec/models/scimitar/complex_types/email_spec.rb
         | 
| 282 | 
            -
            - spec/models/scimitar/complex_types/address_spec.rb
         | 
| 283 | 
            -
            - spec/requests/controller_configuration_spec.rb
         | 
| 284 | 
            -
            - spec/requests/engine_spec.rb
         | 
| 285 304 | 
             
            - spec/requests/active_record_backed_resources_controller_spec.rb
         | 
| 286 305 | 
             
            - spec/requests/application_controller_spec.rb
         | 
| 306 | 
            +
            - spec/requests/controller_configuration_spec.rb
         | 
| 307 | 
            +
            - spec/requests/engine_spec.rb
         | 
| 308 | 
            +
            - spec/spec_helper.rb
         | 
| 287 309 | 
             
            - spec/spec_helper_spec.rb
         | 
| 288 310 | 
             
            - spec/support/hash_with_indifferent_case_insensitive_access_spec.rb
         | 
| 289 | 
            -
            - spec/controllers/scimitar/schemas_controller_spec.rb
         | 
| 290 | 
            -
            - spec/controllers/scimitar/resource_types_controller_spec.rb
         | 
| 291 | 
            -
            - spec/controllers/scimitar/resources_controller_spec.rb
         | 
| 292 | 
            -
            - spec/controllers/scimitar/service_provider_configurations_controller_spec.rb
         | 
| 293 | 
            -
            - spec/controllers/scimitar/application_controller_spec.rb
         | 
| 294 | 
            -
            - spec/apps/dummy/app/models/mock_group.rb
         | 
| 295 | 
            -
            - spec/apps/dummy/app/models/mock_user.rb
         | 
| 296 | 
            -
            - spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb
         | 
| 297 | 
            -
            - spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb
         | 
| 298 | 
            -
            - spec/apps/dummy/app/controllers/mock_groups_controller.rb
         | 
| 299 | 
            -
            - spec/apps/dummy/app/controllers/mock_users_controller.rb
         | 
| 300 | 
            -
            - spec/apps/dummy/config/routes.rb
         | 
| 301 | 
            -
            - spec/apps/dummy/config/environments/test.rb
         | 
| 302 | 
            -
            - spec/apps/dummy/config/environment.rb
         | 
| 303 | 
            -
            - spec/apps/dummy/config/application.rb
         | 
| 304 | 
            -
            - spec/apps/dummy/config/boot.rb
         | 
| 305 | 
            -
            - spec/apps/dummy/config/initializers/session_store.rb
         | 
| 306 | 
            -
            - spec/apps/dummy/config/initializers/cookies_serializer.rb
         | 
| 307 | 
            -
            - spec/apps/dummy/config/initializers/scimitar.rb
         | 
| 308 | 
            -
            - spec/apps/dummy/db/schema.rb
         | 
| 309 | 
            -
            - spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb
         | 
| 310 | 
            -
            - spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb
         | 
| 311 | 
            -
            - spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb
         | 
| 312 | 
            -
            - spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb
         |