Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AM::Error.full_message to remove ":base" #48871

Merged
merged 6 commits into from Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 8 additions & 3 deletions activemodel/CHANGELOG.md
@@ -1,9 +1,14 @@
* Add a load hook for `ActiveModel::Model` (named `active_model`) to match the load hook for `ActiveRecord::Base` and
allow for overriding aspects of the `ActiveModel::Model` class.
* Error.full_message now strips ":base" from the message.

*zzak*

* Add a load hook for `ActiveModel::Model` (named `active_model`) to match the load hook for
`ActiveRecord::Base` and allow for overriding aspects of the `ActiveModel::Model` class.

*Lewis Buckley*

* Improve password length validation in ActiveModel::SecurePassword to consider byte size for BCrypt compatibility.
* Improve password length validation in ActiveModel::SecurePassword to consider byte size for BCrypt
compatibility.

The previous password length validation only considered the character count, which may not
accurately reflect the 72-byte size limit imposed by BCrypt. This change updates the validation
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/error.rb
Expand Up @@ -49,6 +49,8 @@ def self.full_message(attribute, message, base) # :nodoc:
defaults << :"errors.format"
defaults << "%{attribute} %{message}"

attribute = attribute.remove(/\.base\z/)

attr_name = attribute.tr(".", "_").humanize
attr_name = base_class.human_attribute_name(attribute, {
default: attr_name,
Expand Down
5 changes: 5 additions & 0 deletions activemodel/test/cases/error_test.rb
Expand Up @@ -217,6 +217,11 @@ def test_initialize
assert_not_equal error, person
end

test "full_message returns the given message when the attribute contains base" do
error = ActiveModel::Error.new(Person.new, :"foo.base", "press the button")
assert_equal "foo press the button", error.full_message
end

# details

test "details which ignores callback and message options" do
Expand Down
14 changes: 5 additions & 9 deletions activerecord/lib/active_record/autosave_association.rb
Expand Up @@ -359,15 +359,11 @@ def association_valid?(reflection, record, index = nil)
end

def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
normalized_attribute =
if indexed_attribute
"#{reflection.name}[#{index}]"
else
reflection.name
end

normalized_attribute = "#{normalized_attribute}.#{attribute}" if attribute != :base
normalized_attribute
if indexed_attribute
"#{reflection.name}[#{index}].#{attribute}"
else
"#{reflection.name}.#{attribute}"
end
end

# Is used as an around_save callback to check while saving a collection
Expand Down
51 changes: 50 additions & 1 deletion activerecord/test/cases/autosave_association_test.rb
Expand Up @@ -597,7 +597,56 @@ def self.name; "Person"; end
assert_predicate reference_valid, :valid?
assert_not_predicate reference_invalid, :valid?
assert_not_predicate p, :valid?
assert_equal [{ error: "should be favorite" }], p.errors.details[:"references[1]"]
assert_equal [{ error: "should be favorite" }], p.errors.details[:"references[1].base"]
assert_equal "should be favorite", p.errors[:"references[1].base"].first
rafaelfranca marked this conversation as resolved.
Show resolved Hide resolved
end

def test_indexed_errors_should_be_properly_translated
old_i18n_customize_full_message = ActiveModel::Error.i18n_customize_full_message
ActiveModel::Error.i18n_customize_full_message = true
I18n.backend.store_translations(
:en,
activerecord: {
errors: {
models: {
"person/references": {
format: "%{message}"
}
}
}
}
)
reference = Class.new(ActiveRecord::Base) do
self.table_name = "references"
def self.name; "Reference"; end

validate :should_be_favorite
validates_presence_of :job_id

private
def should_be_favorite
errors.add(:base, "should be favorite") unless favorite?
end
end

person = Class.new(ActiveRecord::Base) do
self.table_name = "people"
has_many :references, autosave: true, index_errors: true, anonymous_class: reference
def self.name; "Person"; end
end

p = person.new
reference_valid = reference.new(favorite: true, job_id: 1)
reference_invalid = reference.new(favorite: false)
p.references = [reference_valid, reference_invalid]

assert_predicate reference_valid, :valid?
assert_not_predicate reference_invalid, :valid?
assert_not_predicate p, :valid?
assert_equal ["should be favorite", "can’t be blank"], p.errors.full_messages
ensure
ActiveModel::Error.i18n_customize_full_message = old_i18n_customize_full_message
I18n.backend = I18n::Backend::Simple.new
end

def test_errors_details_should_be_indexed_when_global_flag_is_set
Expand Down