-
Notifications
You must be signed in to change notification settings - Fork 3
Detecting property changes
Sometimes, you might need to detect whether a property has been changed in an Update
operation, so
that you can run some piece of business logic. If you want to do it after saving, you can usually
accomplish it with your ORM, so we're not going to explore that scenario. However, with contracts
you can also detect when a property is being changed before saving, by calling the #changed?
method.
For example, when a user updates their password, we might want to send a hash of the password to a third-party service to ensure it's not a common password. Here's how we could accomplish that:
# app/resources/api/v1/user/operation/update.rb
module API
module V1
module User
module Operation
class Update < Pragma::Operation::Update
step :check_password_safety!, before: 'contract.default.save'
failure :handle_unsafe_password!, after: :check_password_safety!
def check_password_safety!(options)
return true unless options['contract.default'].changed?(:password)
PasswordChecker.safe_password?(options['contract.default'].password)
end
def handle_unsafe_password!(options)
options['result.response'] = Pragma::Operation::Response::UnprocessableEntity.new(
errors: { password: ['is not safe'] },
).decorate_with(Pragma::Decorator::Error)
end
end
end
end
end
end
As you can see, we are adding two new steps that will run just before contract.default.save
, whose
job is to detect whether the password was changed and, if it was, to call an external service to
check whether the new password is safe. The return value of the service is then used to determine
whether to move to the failure track, which takes care of responding with an appropriate error
message.