Last active
April 18, 2021 08:25
-
-
Save fran-worley/5417e88fa9f293e6ff0f to your computer and use it in GitHub Desktop.
Reform/ Dry-V validation examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
en: | |
errors: | |
rules: | |
title: | |
filled?: "can't be blank" | |
first_name: | |
filled?: "can't be blank" | |
last_name: | |
filled?: "can't be blank" | |
email: | |
filled?: "can't be blank" | |
unique_email?: "an active account already exists with that email address" | |
account_exists_for_email?: "an account can't be found for provided email address" | |
format?: "not a valid email address" | |
password: | |
filled?: "can't be blank" | |
min_size?: "must be at least %{num} characters long" | |
account_authenticated?: "is incorrect, please re-enter your password" | |
password_confirmation: | |
filled?: "can't be blank" | |
eql?: "doesn't agree to password" | |
assignment_id: | |
filled?: "can't be blank" | |
int?: "must be integer" | |
within_client_scope?: "invalid profile" | |
unique?: "you can only have one assignment per profile" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'reform/form/coercion' | |
require "reform/form/dry" | |
class LoginForm < Reform::Form | |
include Coercion | |
include Reform::Form::Dry::Validations | |
#form object without a AR model | |
#so override initialize | |
def initialize | |
super(OpenStruct.new) | |
end | |
properties :email, :password, type: String | |
property :remember_me, type: Virtus::Attribute::Boolean | |
attr_accessor :user | |
validation :default do | |
key(:email, &:filled?) | |
key(:password, &:filled?) | |
end | |
validation :account_exists, if: :default do | |
configure do |config| | |
config.messages_file = 'config/error_messages.yml' | |
end | |
key(:email) { |value| value.account_exists_for_email? } | |
def account_exists_for_email?(value) | |
form.user = User.find_by(email: value.downcase) | |
form.user.present? | |
end | |
end | |
validation :valid_password, if: :account_exists do | |
configure do |config| | |
config.messages_file = 'config/error_messages.yml' | |
end | |
key(:password) { |value| value.account_authenticated? } | |
def account_authenticated?(value) | |
form.user.authenticate(value) | |
end | |
end | |
end #class LoginForm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ActiveRecord::Base | |
has_secure_password validations: false | |
has_many :assignments, dependent: :destroy | |
belongs_to :organisation | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'reform/form/coercion' | |
require "reform/form/dry" | |
require 'disposable/twin/parent' | |
class UserForm < Reform::Form | |
feature Coercion | |
feature Parent | |
feature Reform::Form::Dry::Validations | |
properties :title, :first_name, :last_name, :suffix, :email, type: String | |
property :login, type: Virtus::Attribute::Boolean | |
property :password, read: false, type: String | |
property :password_confirmation, virtual: true, type: String | |
collection :assignments, populator: :assignments!, skip_if: :all_blank do | |
property :id, type: Integer, writeable: false | |
property :_destroy, virtual: true | |
property :assignment_id, type: Integer | |
property :role, type: String | |
validation :default do | |
configure { |config| config.messages_file = 'config/error_messages.yml' } | |
key(:assignment_id) {|assignment_id| assignment_id.filled? & assignment_id.int? } | |
end | |
validation :valid_assignment, if: :default do | |
configure { |config| config.messages_file = 'config/error_messages.yml' } | |
key(:assignment_id) { |assignment_id| assignment_id.within_client_scope? & assignment_id.unique? } | |
#makes use of disposables `feature Parent` to access siblings | |
#should return false if the assignment is not part of the correct organisation | |
def within_client_scope?(value) | |
Assignment.where(organisation_id: form.parent.organisation_id).pluck(:id).include?(value) | |
end | |
#makes use of disposables `feature Parent` to access siblings | |
#should return false is it is not unique | |
def unique?(value) | |
!form.parent.assignments.map{|a| a.assignment_id == value unless a == form }.include?(true) | |
end | |
end | |
end | |
validation :default do | |
configure { |config| config.messages_file = 'config/error_messages.yml' } | |
key(:title, &:filled?) | |
key(:first_name, &:filled?) | |
key(:last_name, &:filled?) | |
key(:password){ |password| password.none? | (password.filled? & password.min_size?(6)) } | |
key(:password_confirmation){ |pass_conf| password.none? | pass_conf.filled? } | |
key(:login, &:bool?) | |
#It appears that there are some issues with high-level rules. | |
#https://github.com/dryrb/dry-validation/issues/50 | |
#at present this doesn't work: | |
#key(:email) { |email| email.none? | email.format?(/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i) } | |
#rule(:require_email) do | |
# rule(:login).true? > rule(:email).filled? | |
#end | |
#So i'm temporarily using the form object that reform provides: | |
key(:email) do |email| | |
email.optional? | (email.filled? & email.format?(/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i)) | |
end | |
def optional?(value) | |
form.login != true | |
end | |
#error messages are not generated correctly for high level rules | |
#https://github.com/dryrb/dry-validation/issues/47 | |
rule(:validate_password) do | |
rule(:login).true? > (rule(:password).filled? & rule(:password_confirmation).filled? & rule(:password_confirmation, eql?: [:password, :password_confirmation])) | |
end | |
#will become part of dry-v in future updates | |
def true?(value) | |
value === true | |
end | |
end | |
validation :unique_email, if: :default do | |
configure { |config| config.messages_file = 'config/error_messages.yml' } | |
key(:email) { |email| email.none? | email.unique_email?} | |
def unique_email?(value) | |
User.where(deleted: false, email: value).where.not(id: form.id).blank? | |
end | |
end | |
def assignments!(collection:, fragment:, index:, **) | |
return collection.insert(index, model.assignments.new) if fragment["id"].blank? && fragment["_destroy"] != "true" | |
deserialized_item = collection.find { |item| item.id.to_s == fragment["id"] } | |
if fragment["_destroy"] == "true" # don't process if it's getting removed! | |
collection.delete(deserialized_item) | |
return skip! | |
end | |
deserialized_item | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment