Skip to content

Commit

Permalink
Add stricter address validations
Browse files Browse the repository at this point in the history
Updates the address validations to be stricter. We now require at least
a single letter in the street part of the address, only letters and
punctuation in the town / city name (no numbers), and at least a letter
or digit in the house name / number field.
  • Loading branch information
rjlynch committed Dec 23, 2024
1 parent 815b7d4 commit 68cb793
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 20 deletions.
28 changes: 25 additions & 3 deletions app/forms/address_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class AddressForm < Form
ADDRESS_MAX_CHARS = 100
POSTCODE_MAX_CHARS = 11

ADDRESS_LINE_1_VALIDATION = /\A(?=.*[a-zA-Z0-9])[\w\s,.'-]+\z/
ADDRESS_LINE_2_VALIDATION = /\A(?=.*[a-zA-Z])[\w\s,.'-]+\z/
ADDRESS_LINE_3_VALIDATION = /\A[a-zA-Z\s,.'-]+\z/

validates :address_line_1, presence: {message: i18n_error_message(:address_line_1_blank)}
validates :address_line_2, presence: {message: i18n_error_message(:address_line_2_blank)}
validates :address_line_3, presence: {message: i18n_error_message(:address_line_3_blank)}
Expand All @@ -23,9 +27,9 @@ class AddressForm < Form
validates :address_line_4, length: {maximum: ADDRESS_MAX_CHARS, message: i18n_error_message(:address_line_max_chars)}
validates :postcode, length: {maximum: POSTCODE_MAX_CHARS, message: i18n_error_message(:postcode_max_chars)}

validates :address_line_1, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)}
validates :address_line_2, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)}
validates :address_line_3, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)}
validate :validate_address_line_1, if: -> { address_line_1.present? }
validate :validate_address_line_2, if: -> { address_line_2.present? }
validate :validate_address_line_3, if: -> { address_line_3.present? }
validates :address_line_4, format: {with: ADDRESS_REGEX_FILTER, message: i18n_error_message(:address_format)}

validate :postcode_is_valid, if: -> { postcode.present? }
Expand All @@ -51,4 +55,22 @@ def postcode_is_valid
errors.add(:postcode, i18n_errors_path(:postcode_format))
end
end

def validate_address_line_1
unless ADDRESS_REGEX_FILTER.match(address_line_1) && ADDRESS_LINE_1_VALIDATION.match(address_line_1)
errors.add(:address_line_1, i18n_errors_path(:address_format))
end
end

def validate_address_line_2
unless ADDRESS_REGEX_FILTER.match(address_line_2) && ADDRESS_LINE_2_VALIDATION.match(address_line_2)
errors.add(:address_line_2, i18n_errors_path(:address_format))
end
end

def validate_address_line_3
unless ADDRESS_REGEX_FILTER.match(address_line_3) && ADDRESS_LINE_3_VALIDATION.match(address_line_3)
errors.add(:address_line_3, i18n_errors_path(:address_format))
end
end
end
92 changes: 75 additions & 17 deletions spec/forms/address_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
end

context "address lines too long" do
let(:over_one_hundred_chars) { Array.new(101) { [("a".."z"), ("A".."Z"), ("0".."9")].map(&:to_a).flatten.sample }.join }
let(:over_one_hundred_chars) { Array.new(101) { [("a".."z"), ("A".."Z")].map(&:to_a).flatten.sample }.join }
let(:claim_params) do
{
address_line_1: over_one_hundred_chars,
Expand All @@ -77,25 +77,83 @@
end

context "address lines with format errors" do
let(:claim_params) do
{
address_line_1: "#123",
address_line_2: "Main $treet",
address_line_3: "$ome City",
address_line_4: "$som County",
postcode: "XXX XXXX"
}
context "with unpermitted characters" do
let(:claim_params) do
{
address_line_1: "#123",
address_line_2: "Main $treet",
address_line_3: "$ome City",
address_line_4: "$som County",
postcode: "XXX XXXX"
}
end

it "is invalid with format errors" do
is_expected.not_to be_valid

expect(form.errors.size).to eq 5
expect(form.errors[:address_line_1]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:address_line_2]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:address_line_3]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:address_line_4]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:postcode]).to eq([form.i18n_errors_path(:postcode_format)])
end
end

it "is invalid with too format errors" do
is_expected.not_to be_valid
context "with invalid looking address" do
context "with an invalid line 1" do
let(:claim_params) do
{
address_line_1: ".",
address_line_2: "10 Downing Street",
address_line_3: "London",
postcode: "SW1A 2AA"
}
end

it "is invalid with format errors" do
is_expected.not_to be_valid

expect(form.errors.size).to eq 1
expect(form.errors[:address_line_1]).to eq([form.i18n_errors_path(:address_format)])
end
end

expect(form.errors.size).to eq 5
expect(form.errors[:address_line_1]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:address_line_2]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:address_line_3]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:address_line_4]).to eq([form.i18n_errors_path(:address_format)])
expect(form.errors[:postcode]).to eq([form.i18n_errors_path(:postcode_format)])
context "with an invalid line 2" do
let(:claim_params) do
{
address_line_1: "Flat 1",
address_line_2: ".",
address_line_3: "London",
postcode: "SW1A 2AA"
}
end

it "is invalid with format errors" do
is_expected.not_to be_valid

expect(form.errors.size).to eq 1
expect(form.errors[:address_line_2]).to eq([form.i18n_errors_path(:address_format)])
end
end

context "with an invalid line 3" do
let(:claim_params) do
{
address_line_1: "Flat 1",
address_line_2: "10 Downing Street",
address_line_3: "123",
postcode: "SW1A 2AA"
}
end

it "is invalid with format errors" do
is_expected.not_to be_valid

expect(form.errors.size).to eq 1
expect(form.errors[:address_line_3]).to eq([form.i18n_errors_path(:address_format)])
end
end
end
end
end
Expand Down

0 comments on commit 68cb793

Please sign in to comment.