grape icon indicating copy to clipboard operation
grape copied to clipboard

Support nested attribute names for validation error messages

Open amrrbakry opened this issue 6 years ago • 6 comments

Hello,

I'm trying to override a nested attribute's name that gets show in the validation message, but it doesn't seem possible for nested params

I want to override registration[total_capacity] attribute name:

my params:

params :sessions_params do
  optional :registration_allowed, type: Boolean, desc: 'registration allowed for session?'
  optional :registration, type: Hash, desc: 'session registration settings' do
    requires :total_capacity, type: Integer, desc: 'session registration total capacity', message: :name_required
    requires :waiting_list_enabled, type: Boolean, desc: 'is session registration waiting list enabled?'
  end
end

en.yml

en:
  grape:
    errors:
      format: ! '%{attributes} %{message}'
      messages:
        name_required: 'must be present'
      attributes:
        registration:
          total_capacity: 'Total capacity'

expected error message if total capacity is not sent:

"Total capacity must be present"

actual error message:

"registration[total_capacity] must be present"

is this not possible or is there a problem with my code?

using grape 0.16.2, ruby 2.3.3, rails 4.2

thanks

amrrbakry avatar Nov 20 '19 13:11 amrrbakry

If you put a project up that reproduces this I can try to help.

dblock avatar Nov 20 '19 16:11 dblock

Hi @dblock

here's a project with steps to reproduce in the README:

https://github.com/amrrbakry/grape-nested-params-validation

:+1:

amrrbakry avatar Nov 20 '19 19:11 amrrbakry

@amrrbakry I tried it. Looked like a bug at first, but is more like a non-feature. Looking at https://github.com/ruby-grape/grape/blob/master/lib/grape/exceptions/base.rb#L73 is getting called with registration[total_capacity], so the following en.yml yields what you expect:

      attributes:
        registration[total_capacity]: '...'

This is pretty annoying and we should be supporting the syntax that you were trying to use above with nested attributes, and hopefully preserving backwards compatibility.

Would you care to write some specs and maybe implement this?

dblock avatar Nov 24 '19 16:11 dblock

Thank you, @dblock. I'd be happy to help with this. I'll take a look and see what I can do :+1:

amrrbakry avatar Nov 24 '19 20:11 amrrbakry

Hey @dblock, I need some help/opinion for the ideal way to tackle this. it seems that ParamsScope class constructs the full name of the param as a string (e.g. "registration[total_capacity]") here: https://github.com/ruby-grape/grape/blob/512d4e3494dbd9804a87247f07e2cdd9c3629aef/lib/grape/validations/params_scope.rb#L76 before passing it to the Validation class for translation.

do you suggest a change to the full_name method or is it better to try to extract the names of the nested attributes from the string before the translation?

amrrbakry avatar Nov 26 '19 12:11 amrrbakry

Without digging how it's used I think full_name could return a structure (array?) and that's what we would be passing around until we need a string representation of it.

dblock avatar Nov 26 '19 14:11 dblock