Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle from activerecord error(s) while saving the record #58

Closed
kuldeepaggarwal opened this issue Jul 21, 2023 · 7 comments
Closed

Handle from activerecord error(s) while saving the record #58

kuldeepaggarwal opened this issue Jul 21, 2023 · 7 comments

Comments

@kuldeepaggarwal
Copy link

kuldeepaggarwal commented Jul 21, 2023

SCIMitar gem relies on the fact that Rails throw ActiveRecord::RecordInvalid only if the record is invalid however, Rails can also raise RecordNotSaved error in case of the object is not stored.

In case of RecordNotSaved, we should return ResourceInvalidError error(status_code=400) from SCIMitar instead of 500 status code.

ErrorResponse.new(status: 500, detail: exception.message)

activerecord-rescue_from_duplicate is a gem that we can use to rescue from DB level unique errors in case of race condition.

Adding DB level unique constraint guarantees uniqueness else we could have duplicate records.

And activerecord-rescue_from_duplicate raises RecordNotSaved error in case we receive unique validation error from MYSQL.
Note: SCIM server should respond with 409 in this case.

Proposal

So, I am proposing a slight change in the implementation:

def rescuable_exceptions
  [ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved]
end

def save!(record)
  record.save!

rescue *rescuable_exceptions # here is the slight change
  joined_errors = record.errors.full_messages.join('; ')

  # https://tools.ietf.org/html/rfc7644#page-12
  #
  #   If the service provider determines that the creation of the requested
  #   resource conflicts with existing resources (e.g., a "User" resource
  #   with a duplicate "userName"), the service provider MUST return HTTP
  #   status code 409 (Conflict) with a "scimType" error code of
  #   "uniqueness"
  #
  if record.errors.any? { | e | e.type == :taken }
    raise Scimitar::ErrorResponse.new(
      status:   409,
      scimType: 'uniqueness',
      detail:   joined_errors
    )
  else
    raise Scimitar::ResourceInvalidError.new(joined_errors)
  end
end

This way, this will be extendible in the future for the consumer(like us) to add more custom exceptions in the list if we want to return Scimitar::ResourceInvalidError for particular exceptions.

@pond
Copy link
Member

pond commented Jul 21, 2023

No objections in principle! Are you thinking of creating a PR or wanting us to do this from our side based on the suggestion in this GitHub issue?

@kuldeepaggarwal
Copy link
Author

I can raise the PR if we are okay with the approach.

@pond
Copy link
Member

pond commented Nov 15, 2023

@kuldeepaggarwal (Belatedly, sorry) Yes, something like that would work. Please note some minor changes to the code in that area in the current branch, with the bulk of the actual exception handling moved into a new method but otherwise, the idea of rescuing a configurable list of exceptions would be applied in the same way as you suggest.

@pond
Copy link
Member

pond commented Jan 11, 2024

Since I've allocated myself a couple of days to work on Scimitar backlog stuff, I'm implementing this now, so no need for a new PR at this point.

@gsar
Copy link
Contributor

gsar commented Jan 11, 2024

@pond please also include ActiveRecord::RecordNotUnique in rescuable_exceptions. thanks!

bagp1 added a commit that referenced this issue Jan 12, 2024
Implement suggestion from #58, with test coverage
@pond
Copy link
Member

pond commented Jan 14, 2024

This is now in v2.7.0.

@pond pond closed this as completed Jan 14, 2024
@pond
Copy link
Member

pond commented Jan 15, 2024

...and v1.8.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants