README.md in tram-policy-0.1.1 vs README.md in tram-policy-0.2.0

- old
+ new

@@ -41,11 +41,11 @@ option :text, proc(&:to_s), default: -> { article.text } # define what methods and in what order we should use to validate an article validate :title_presence validate :subtitle_presence - validate :text_presence + validate { errors.add :empty, field: "text", level: "error" if text.empty? } private def title_presence return unless title.empty? @@ -57,17 +57,10 @@ def subtitle_presence return unless subtitle.empty? # Notice that we can set another level errors.add "Subtitle is empty", field: "subtitle", level: "warning" end - - def text_presence - return unless text.empty? - # Adds an error with a translated message. All fields are available - # both as error tags, and I18n translation options - errors.add :empty_text, field: "text", level: "error" - end end ``` Because validation is the only responsibility of a policy, we don't need to call it explicitly. Policy initializer will perform all the checks immediately, memoizing the results into `errors` array. The methods `#valid?`, `#invalid?` and `#validate!` just check those `#errors`. @@ -124,40 +117,44 @@ private def article_readiness # Collects errors tagged by level: "error" from "nested" policy - others = Article::ReadinessPolicy[article].errors.by_tags(level: "error") + readiness_errors = Article::ReadinessPolicy[article].errors.by_tags(level: "error") # Merges collected errors to the current ones. - # New errors are tagged by source: "readiness". - # Notice the block takes _hashified_ errors. - errors.merge(others) { |hash| hash[:source] = "readiness" } + # New errors are also tagged by source: "readiness". + errors.merge(readiness_errors, source: "readiness") end def article_selection errors.add "Not selected", field: "selected", level: "info" unless selected end end ``` -As mentioned above, sending a symbolic key to the `errors#add` means the key should be translated by [I18n][i18n]. The only magic under the hood is that a scope for the translation is taken from the full name of current class. All tags are available as options: +As mentioned above, sending a symbolic key to the `errors#add` means the key should be translated by [I18n][i18n]. The only magic under the hood concerns a scope for the translation. By default it is taken from the full name of current class prepended with `"evil.client.errors"`. +> You can redefine the scope by reloading private method `.scope` of the policy. + +All tags are available as options: + ```ruby class Article::PublicationPolicy < Tram::Policy # ... - errors.add :empty_text, field: "text", level: "error" + errors.add :empty, field: "text", level: "error" # ... end ``` ```yaml # /config/locales/en.yml --- en: - article/publication_policy: - empty_text: "Validation %{level}: %{field} is empty" + tram-policy: + article/publication_policy: + empty: "Validation %{level}: %{field} is empty" ``` This will provide error message "Validation error: text is empty". The last thing to say is about exceptions. When you use `validate!` it raises `Tram::Policy::ValidationError` (subclass of `RuntimeError`). Its message is built from selected errors (taking into account a `validation!` filter). @@ -192,18 +189,10 @@ # ... end ``` -### `if` - -[WIP] Not implemented (coming soon in v0.1.0) - -### `unless` - -[WIP] Not implemented (coming soon in v0.1.0) - ## RSpec matchers RSpec matchers defined in a file `tram-policy/matcher` (not loaded in runtime). Use `be_invalid_at` matcher to check whether a policy has errors with given tags. @@ -295,12 +284,13 @@ ```yaml # config/tram-policies.en.yml --- en: - user/readiness_policy: - blank_name: translation missing - blank_email: translation missing + tram-policy: + user/readiness_policy: + blank_name: translation missing + blank_email: translation missing ``` ```ruby # spec/policies/user/readiness_policy_spec.rb require "spec_helper"