Skip to content

Detecting property changes

Alessandro Desantis edited this page Aug 12, 2018 · 3 revisions

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.

Clone this wiki locally