Collection of ActiveModel validators for rails projects with focus on composition of standalone policy objects.
gem "tram-validators"
Below is a short review of available validators. Read the specs for more details:
Checks that a value satisfies a contract, represented by a standalone validator (policy object). It applies policy validator, and collects its messages under corresponding keys.
require "tram-validators" # defines `validity` validator
class SpecificPolicy < SimpleDelegator
include ActiveModel::Validations
validates :bar, presence: true
validates :itself, validity: true # validates wrapped object per se
end
# PolicyObject.new(record.foo).valid? == true
# adds message with i18 translation `foo.contract_specific_policy`
validates :foo, contract: { policy: SpecificPolicy }
# collects messages from policy under their original keys (`bar`)
validates :foo, contract: { policy: PolicyObject, original_keys: true }
# collects messages from policy under nested keys (`foo[bar]`)
validates :foo, contract: { policy: PolicyObject, nested_keys: true }
When you use :nested_keys
, the keys :base
and :itself
will be excluded from chain of nesting.
That's why when PolicyObject
is invalid at :itself
, the last definition will collect error under the key foo
, not the foo[itself]
.
Checks that an attribute is valid per se. It collects original error messages under corresponding keys.
# record.foo.valid? == true
# adds message with i18 translation `foo.valid`
validates :foo, validity: true
# collects messages from invalid value under their original keys (`bar`)
validates :foo, validity: { original_keys: true }
# collects messages from invalid value under nested keys (`foo[bar]`)
validates :foo, validity: { nested_keys: true }
Applies validation rule to every element of the collection (that responds to to_a
).
# Checks that every element of record.list is present
# collects original errors under keys `list[i]` (i for index of invalid item)
validates :list, each: { presence: true }
Validates value by checking another method depending on it.
# Validates `user_id` by checking that `user.role` (depending on user_id) is set
# adds error `user_role_presence` to the original attribute `user_id`
validates :user_id, outcome: { value: "user.role", presence: true }
This technics is useful in form objects where you should attach errors to the original fields accessible to the user.
Compares a value of some attribute to a value of another attribute or method chain. Supports all keys from the standard rails numericality validator.
# record.foo < record.bar.baz
# adds error named `less_than_bar_baz` under the key `foo`
validates :foo, consistency: { less_than: "bar.baz" }
Compares size of array to given value or another attribute. Supports all keys from the standard rails numericality validator.
# record.names.size < 6
# adds error named `size_less_than` under the key `names`
validates :names, size: { less_than: 6 }
# record.values.size == record.parent&.names&.size
# adds error named `size_equal_to_parent_names_size` under the key `names`
validates :values, size: { equal_to: "parent.names.size" }
This is an AR-dependent validator, that checks an instance can be extracted from database by given key.
# Checks that User.find_by(record.user_key).present?
validates :user_key, reference: { model: User, find_by: :key }
Like the outcome validator above, it can be useful for validation of form objects.
The gem is available as open source under the terms of the MIT License.