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

Users can CRUD deputy assignments #363

Merged
merged 11 commits into from
Nov 15, 2021
Merged

Users can CRUD deputy assignments #363

merged 11 commits into from
Nov 15, 2021

Conversation

rschenk
Copy link
Contributor

@rschenk rschenk commented Nov 11, 2021

A few things to note:

  • I modified the database schema of the deputy_assignments table, added another column which allows me to write a database level uniqueness constraint that all active DeputyAssignments must have a unique pairing of (primary, deputy) but inactive DeputyAssignments can have multiples. There's now a big comment on DeputyAssignment class explaining how this works.
  • There's a big form object that accepts a user's webaccess id, then does all the legwork of creating and validating a DeputyAssignment for them. The logic for this is broken down in Allow an RMD user to assign another RMD user as their delegate #269. It also puts a lot of effort into making the validation errors look reasonable to the user on the screen.
  • There's also a much smaller service object used to delete/deactivate DeputyAssignments
  • Based on the fact that we renamed Delegates/Deputies/Proxies three times in a week, I put everything in a translation file. While I was at it, I just put the entire user profile management navigation bar into the translations as well.
  • I added ViewComponent for making the Proxies UI

There is one thing I noticed when coding this up, it seems like the Rails-UJS javascript is being loaded/initialized twice. We should look into that, because any button with data: { confirm: ... } will prompt you twice.

Closes #269

Comment on lines 61 to 67
if deputy.persisted?
existing_deputy_assignment = DeputyAssignment.active.find_by(
primary: primary,
deputy: deputy
)
raise AlreadyAssigned if existing_deputy_assignment.present?
end
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI if you are reviewing this commit-by-commit, CodeClimate flagged this and I agree. I moved this check out of this method and into its own in a future commit

Copy link
Contributor

@awead awead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit, I had great difficulty getting through this. I understand there's a lot to get done here, so it's going to be a complicated PR. My main concerns are with the form object which doesn't seem to be sustainably written. In other words, it's going to require a lot of cognitive load when we have to revisit it in the future. Relying on raising and catching exceptions is thornier than using errors directly. Also, there might some other concerns regarding the PsuIdentity end that could be shoved off to the gem and then it's be one less "branch" condition to deal with here.

I'm happy to pair up or give more detailed feedback, so I'll leave at this for now.

app/models/deputy_assignment.rb Show resolved Hide resolved
return if active?
return if active_uniqueness_key == id

update_column(:active_uniqueness_key, id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return if active? || active_uniqueness_key == id ?


# See note at the top of this class for what this does and how.
self.active_uniqueness_key ||= if is_active?
0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is coming up uncovered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that rcov reported this too, even though it is covered

# If we are _creating_ an inactive record,
# init with temp value of current time in millis.
# Will update it to the row's id once we know it
(Time.zone.now.to_f * 1000).to_i
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also uncovered too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that too, except it totally has tests so I don't know what rcov's deal is

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's weirded out by some combo of the format/indentation/comments here?

new_user.last_name = psu_identity.family_name
new_user.psu_identity = psu_identity

raise ErrorCreatingUser unless new_user.valid?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just add the errors here directly instead of raise/catch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could add errors here, but I still need to raise because I need a way to short-circuit the #save method if a User cannot be created, i.e. the calling method should not proceed to try to build a DeputyAssignment if the deputy User is invalid and can't be saved.

Now Avdi Grimm claims that you should never use exceptions for control flow and that you should use try / catch for this purpose instead. The thing is, though, I've never seen anyone actually ever do that. 🤣

errors.add(:base, :identity_service_error)
rescue IdentityNotFound
errors.add(:deputy_webaccess_id, :not_found)
rescue AlreadyAssigned
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line isn't covered.

app/forms/new_deputy_assignment_form.rb Show resolved Hide resolved
errors.add(:base, :error_creating_user)
rescue StandardError
errors.add(:base, :unknown_error)
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rescuing all the errors strikes me as a bit of a code smell. Could we do the same thing with nil checks, which are faster, and then add the errors as we go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line exists to catch network errors coming from the PsuIdentity gem. Network timeouts, 4xx responses, etc, which could not be handled by nil checks. As best I could tell, that gem does not have a base class for its errors, and right now uses Faraday (which does have a base class). However, that gem could easily not use Faraday in future versions, so it would be foolish to catch Faraday error classes here. If PsuIdentity had its own base class for errors, that's what I'd use on this line

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rschenk rschenk force-pushed the 269-user-delegate-ui branch from 70d057f to 4aae43f Compare November 12, 2021 19:16
@rschenk
Copy link
Contributor Author

rschenk commented Nov 12, 2021

Relying on raising and catching exceptions is thornier than using errors directly

Adam, I refactored that class to not use (as many) catches, give the new version a perusal

@rschenk rschenk requested a review from awead November 12, 2021 19:19
Copy link
Contributor

@ajkiessl ajkiessl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good 2 go.

@rschenk rschenk merged commit cd41550 into main Nov 15, 2021
@rschenk rschenk deleted the 269-user-delegate-ui branch November 15, 2021 17:09
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

Successfully merging this pull request may close these issues.

Allow an RMD user to assign another RMD user as their delegate
4 participants