Don't count errors for the same field twice

The number of errors in a form includes several errors for the same
field. For example, if a title is mandatory and has to have at least 5
characters, leaving the title blank will result in two errors. So users
will be invited to look for two errors, but they'll only find one field
with errors.

So it's a bit more intuitive to show as many errors as fields having
errors.

Note we're excluding errors on `:base`, which is a bit of a hack for
errors in association fields. For example, if the title of one
translation is not present, `resource.errors.messages` will contain two
elements: one for the translation's title, and one for the `base` field.
This resulted in the count of errors being 2 when there was only one.

Also note I haven't found a way to count errors on all `has_many`
relations. That is, if two translations have a missing title field, only
one error will be mentioned in the message (as it did before this
commit).
This commit is contained in:
Javi Martín
2020-03-11 18:37:28 +01:00
parent 1f2bdce837
commit 1e883af9cd
3 changed files with 45 additions and 2 deletions

View File

@@ -5,7 +5,9 @@
</button> </button>
<strong> <strong>
<%= pluralize resource.errors.count, t("form.error"), t("form.errors") %> <% errors_count = resource.errors.messages.reject { |attribute| attribute == :base }.count %>
<%= pluralize errors_count, t("form.error"), t("form.errors") %>
<% if local_assigns[:message].present? %> <% if local_assigns[:message].present? %>
<%= message %> <%= message %>

View File

@@ -63,7 +63,8 @@ describe "Admin dashboard actions" do
scenario "Renders create form in case data is invalid" do scenario "Renders create form in case data is invalid" do
click_button "Save" click_button "Save"
expect(page).to have_content("errors prevented this Dashboard/Action from being saved.")
expect(page).to have_content("error prevented this Dashboard/Action from being saved.")
end end
end end

View File

@@ -0,0 +1,40 @@
require "rails_helper"
describe "shared errors" do
class DummyModel
include ActiveModel::Model
attr_accessor :title, :description, :days
validates :title, presence: true
validates :description, presence: true, length: { in: 10..100 }
validates :days, numericality: { greater_than: 10 }
end
it "counts the number of fields with errors" do
resource = DummyModel.new(title: "Present", description: "", days: 3)
resource.valid?
render "shared/errors", resource: resource
expect(rendered).to have_content "2 errors"
end
it "doesn't include `base` errors in new records" do
resource = build(:debate, title: "", description: "")
resource.valid?
render "shared/errors", resource: resource
expect(rendered).to have_content "2 errors"
end
it "doesn't include `base` errors in existing records" do
resource = create(:debate)
resource.translations << Debate::Translation.new(title: "Title", description: "", locale: "es")
resource.valid?
render "shared/errors", resource: resource
expect(rendered).to have_content "1 error"
end
end