Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* [#2918](https://github.com/ruby-grape/grape/pull/2918): Skip the dry-types round trip when a value already is the declared type - [@ericproulx](https://github.com/ericproulx).
* [#2917](https://github.com/ruby-grape/grape/pull/2917): Read path captures out of the router's union match instead of re-running the route's pattern - [@ericproulx](https://github.com/ericproulx).
* [#2921](https://github.com/ruby-grape/grape/pull/2921): Pin the router's request-time isolation regressions through requests instead of its instance variables - [@ericproulx](https://github.com/ericproulx).
* [#2934](https://github.com/ruby-grape/grape/pull/2934): Translate `ValidationErrors#full_messages` once instead of on every call - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.

### 4.0.0 (2026-09-07)
Expand Down
14 changes: 12 additions & 2 deletions lib/grape/exceptions/validation_errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,19 @@ def to_json(*_opts)
as_json.to_json
end

# Translated once, when the error is built for its #message, and handed
# out as a copy from then on. Every lookup here is an I18n call of a few
# microseconds, and the README's recipe for answering with the list,
# +error!({ messages: e.full_messages }, 400)+, asked for all of them a
# second time. It also keeps the list the same as #message, which was
# already fixed at that point, if the locale changes in between.
def full_messages
(@full_messages ||= translate_full_messages).dup
end

private

def translate_full_messages
messages = errors.flat_map do |attributes, errs|
errs.map do |error|
translate(
Expand All @@ -39,8 +51,6 @@ def full_messages
messages
end

private

def translate_attributes(keys)
keys.map do |key|
translate(key, scope: 'grape.errors.attributes', default: key.to_s)
Expand Down
9 changes: 9 additions & 0 deletions spec/grape/exceptions/validation_errors_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@
expect(subject.first).to eq('admin_field Can not set admin-only field')
end
end

context 'when the caller changes the array it was given' do
subject(:error) { described_class.new(exceptions: [Grape::Exceptions::Validation.new(params: ['id'], message: :presence)]) }

it 'returns the same messages the next time' do
error.full_messages << 'name is missing'
expect(error.full_messages).to eq(['id is missing'])
end
end
end

context 'api' do
Expand Down
Loading