-
-
Save fran-worley/5734768cc5b4a0160c69d2d60f7ed3c7 to your computer and use it in GitHub Desktop.
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/dry' | |
require 'reform/form/coercion' | |
class AddressForm < Reform::Form | |
feature Reform::Form::Dry | |
feature Reform::Form::Coercion | |
property :is_digital, type: Types::Form::Bool, default: true | |
properties :address1, :address2, :city, :state, :zipcode, :phone, nilify: true # replaces '' with nil | |
validation do | |
configure do | |
# If using the latest reform you could define a base schema | |
# and then you wouldn't need to configure message location each time. | |
config.messages_file = 'config/locales/reform_messages.en.yml' | |
option :postcodes, ::TwitterCldr::Shared::PostalCodes # I like defining dependencies like this for clarity, totally optional | |
option :form # if using the latest reform replace this with { with: {form: true} } in the validation block | |
option :easypost, ::EasyPost::Address # I like defining dependencies like this for clarity, totally optional | |
def valid_zipcode?(zipcode) | |
postcodes.for_territory(:us).valid?(zipcode) | |
end | |
# from memory, predicates require one param even if you don't use it | |
def easypost_validator?(is_digital) | |
address = { | |
street1: form.address1, | |
street2: form.address2, | |
city: form.city, | |
state: form.state, | |
zip: form.zipcode | |
} | |
result = true | |
begin | |
easypost.create_and_verify(address) | |
rescue | |
result = false | |
end | |
Rails.logger.info("EasyPost address validation result for address #{address} result: #{result}") | |
result | |
end | |
end | |
required(:address1).maybe(:str?) # For explicitness I always like to define a type here, even for strings! | |
required(:address2).maybe(:str?) # in Reform, the key will always exist so 'optional' is pointless | |
required(:city).maybe(:str?) | |
required(:state).maybe(:str?) # if this is an int then you should use :int? here (you might want a custom message) | |
required(:zipcode).maybe(:str?, :valid_zipcode?) | |
required(:phone).maybe(:str?, size?: 10) # Your `phone=()` method should have removed the non-digits already | |
# if nils are possible then you'll may need to change this as (from memory) bool assumes true or false | |
required(:is_digital).filled(:bool?) | |
rule(address1: [:is_digital, :address1]) do |is_digital, address1| | |
is_digital.false?.then(address1.filled?) | |
end | |
rule(city: [:is_digital, :city]) do |is_digital, city| | |
is_digital.false?.then(city.filled?) | |
end | |
rule(zipcode: [:is_digital, :zipcode]) do |is_digital, zipcode| | |
is_digital.false?.then(zipcode.filled?) | |
end | |
rule(phone: [:is_digital, :phone]) do |is_digital, phone| | |
is_digital.false?.then(phone.filled?) | |
end | |
# To guard against errors in dependent properties be sure to declare all dependent properties | |
# as you only want this check to run when all their basic checks pass. | |
rule(easypost_validation: [ | |
:is_digital, :address1, :address2, :city, :state, :zipcode | |
]) do |is_digital, address1, address2, city, state, zipcode| # you probably only need to declare is_digital here. | |
is_digital.false?.then(is_digital.easypost_validator?) | |
end | |
end | |
def phone | |
value = super.gsub(/\D/, '') | |
"(#{value[0..2]}) #{value[3..5]}-#{value[6..9]}" | |
end | |
def phone=(value) | |
super(value.gsub(/\D/, '')) | |
end | |
def state=(state) | |
return if state.empty? | |
super(Spree::State.find(state.to_i)) | |
end | |
def zipcode | |
return super if super.length == 5 | |
value = super.gsub(/\D/, '') | |
"#{value[0..4]}-#{value[5..9]}" | |
end | |
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
module GiftCardForms | |
class CheckoutForm < AddressForm | |
property :message | |
property :is_digital, default: false, inherit: true # override the AddressForm where the default is true | |
validation inherit: true do # append this rule to the existing validations in the default block | |
required(:message).filled(:str?) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This assumes that you always validate that address fields are filled, but only run them through your
easypost_validator?
ifis_digital == true
.There are ways to do this in pure dry-validation, but I personally find it's sometimes easier to embrace Reform sometimes!
I've not actually tested this but it should give you an idea of how you could implement this.