README.md in metaractor-2.1.1 vs README.md in metaractor-3.0.0

- old
+ new

@@ -42,11 +42,11 @@ result = HighFiveUser.call # not passing user or user_id result.failure? # => true result.valid? # => false -result.errors +result.error_messages # => ["Required parameters: (user_id or user)"] ``` See Interactor's [README](https://github.com/collectiveidea/interactor/blob/master/README.md) for more information. @@ -66,24 +66,45 @@ Metaractor supports complex required parameter statements and you can chain these together in any manner using `and`, `or`, and `xor`. ```ruby required and: [:token, or: [:recipient_id, :recipient] ] ``` +You can also mark a parameter as required with the `required` option: +```ruby +parameter :user, required: true +``` + ### Optional Parameters As optional parameters have no enforcement, they are merely advisory. ```ruby optional :enable_logging ``` -### Skipping Blank Parameter Removal +### Parameter Options +Metaractor supports arbitrary parameter options. The following are currently built in. +Note that you can specify a block of `required` or `optional` parameters and then use +`parameter` or `parameters` to add options to one or more of them. + +#### Skipping Blank Parameter Removal By default Metaractor removes blank values that are passed in. You may skip this behavior on a per-parameter basis: ```ruby -allow_blank :name +parameter :name, allow_blank: true ``` You may check to see if a parameter exists via `context.has_key?`. +#### Default Values +You can specify a default value for a parameter: +```ruby +optional :role, default: :user +``` + +This works with `allow_blank` and can also be anything that responds to `#call`. +```ruby +parameter :role, allow_blank: true, default: -> { context.default_role } +``` + ### Custom Validation Metaractor supports doing custom validation before any user supplied before_hooks run. ```ruby validate_parameters do if context.foo == :bar @@ -159,10 +180,68 @@ # username: ['must be unique', 'must not be blank'] # } # } ``` +### I18n +As of v3.0.0, metaractor supports i18n along with structured errors. +```ruby +module Users + class UpdateUser + include Metaractor + + optional :is_admin + optional :user + + def call + fail_with_error!( + errors: { + base: :invalid_configuration, + is_admin: :true_or_false, + user: [ title: :blank, username: [:unique, :blank] ] + } + ) + end + end +end +``` + +Locale: +```yaml +en: + errors: + parameters: + invalid_configuration: 'Invalid configuration' + blank: '%{parameter} cannot be blank' + unique: '%{parameter} must be unique' + + users: + is_admin: + true_or_false: 'must be true or false' + user: + username: + unique: 'Username has already been taken' +``` + +Metaractor will attempt to use the namespace of the code that reported the error. +You can see that above with the `users` key in the locale. + +The i18n integration will walk its way from the most specific message to the least specific one, stopping at the first one it can find. +We currently expose the following variables for use in the message: +- `error_key`: the error we added (ex: `blank` or `invalid_configuration`) +- `parameter`: the name of the parameter + +You can also use this feature to work with machine readable keys: +```ruby +result = Users::UpdateUser.call +if result.failure? && + result.errors[:is_admin] == :true_or_false + + # handle this specific case +end +``` + ### Spec Helpers Enable the helpers and/or matchers: ```ruby RSpec.configure do |config| config.include Metaractor::Spec::Helpers @@ -219,12 +298,12 @@ ).at_path(:user, :username) expect(result).to include_errors('user.title cannot be blank') ``` -### Error Output -Metaractor customizes the exception message for `Interactor::Failure`: +### Hash Formatting +Metaractor customizes the output for `Metaractor::Errors#inspect` and `Interactor::Failure`: ``` Interactor::Failure: Errors: {:base=>"NOPE"} @@ -233,13 +312,15 @@ Context: {:parent=>true, :chained=>true} ``` -You can further customize the exception message: +You can further customize the hash formatting: ```ruby -# Configure FailureOutput to use awesome_print -Metaractor::FailureOutput.hash_formatter = ->(hash) { hash.ai } +Metaractor.configure do |config| + # Configure Metaractor to use awesome_print + config.hash_formatter = ->(hash) { hash.ai } +end ``` ### Further Reading For more examples of all of the above approaches, please see the specs.