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

Errors of nested collection are not shown. #527

Open
bayburin opened this issue Apr 12, 2021 · 1 comment
Open

Errors of nested collection are not shown. #527

bayburin opened this issue Apr 12, 2021 · 1 comment

Comments

@bayburin
Copy link

Complete Description of Issue

Hi! I'm using reform 2.5.0 with dry-validations 1.6 into rails 6.0.3 and seeing issue. I'm trying to validate a nested collection of forms from the parent form and output errors for each collection item, but form.errors.messages method returns empty hash.

Steps to reproduce

class WorkForm < Reform::Form
  property :id
  property :claim_id
  property :group_id
  collection :workflows, form: WorkflowForm, populate_if_empty: Workflow

  validation do
    option :form
    config.messages.backend = :i18n

    params do
      required(:group_id).filled(:int?)
      optional(:workflows)
    end
    
    rule(:group_id) do
      key.failure(:already_exist) if Work.where.not(id: form.model.id).where(group_id: value, claim_id: form.claim_id).exists?
    end
    
    rule(:workflows).each do |index:|
      next if value[:id]
      
      # For reproduce I removed any conditions and just raised error to fail validation
      key([:workflows, :sender_id, index]).failure('invalid sender_id')
    end
  end
end

class WorkflowForm < Reform::Form
  property :id
  property :work_id
  property :sender_id
  property :message
end

# Now call the form
irb(main):366:0>  params = { "group_id": 2, "workflows": [{ "sender_id": 4, "message": "workflow message" }] }
irb(main):366:0>  form = WorkForm.new(Work.find(4))
irb(main):366:0>  form.validate(params)
# false
irb(main):366:0>  form.errors.messages
# {}

Expected behavior

I did this validation according to dry-rb documentation:
https://dry-rb.org/gems/dry-validation/1.6/rules/#defining-a-rule-for-each-element-of-an-array

I expect to see something like this:

irb(main):366:0> form.errors.messages
# {"workflows"=>{"sender_id"=>{0=>["invalid sender_id"]}}}

Actual behavior

But now I see an empty hash

irb(main):366:0> form.errors.messages
# {}

Although if you look at the error object, you can see that the validation worked successfully and detected an error into collection:

irb(main):366:0> form.errors.instance_variable_get(:@result)
=> #<Reform::Contract::Result:0x0000563bef736a28 @results=[#<Dry::Validation::Result{:group_id=>2, :workflows=>[{:id=>nil, :claim_id=>nil, :work_id=>nil, :sender_id=>4, :message=>"workflow message"}]} errors={:workflows=>{:sender_id=>{0=>["invalid sender_id"]}}}>], @failure=#<Dry::Validation::Result{:group_id=>2, :workflows=>[{:id=>nil, :claim_id=>nil, :work_id=>nil, :sender_id=>4, :message=>"workflow message"}]} errors={:workflows=>{:sender_id=>{0=>["invalid sender_id"]}}}>>

If I transfer the validation to the WorkflowForm and refuse to iterate the array, there is no such problem, the error is successfully displayed. But I cannot transfer validation to a nested form as I need to compare the data from WorkForm with data from WorkflowForm form.

System configuration

Reform version: 2.5.0
Rails version: 6.0.3
dry-validation version: 1.6.0

@yogeshjain999
Copy link
Member

This works for me

require 'test_helper'                                                                                                             

class ValidateCollectionTest < MiniTest::Spec
  class SongForm < TestForm
    property :title
  end 

  class AlbumForm < TestForm
    collection :songs, form: SongForm

    validation do
      option :form

      params do
        optional(:songs)
      end 

      rule(:songs).each do |index:|
        key([:title, index]).failure('Invalid') if value[:title] == "Wrong"
      end 
    end 
  end 

  let(:song)               { Song.new("Broken") }
  let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
  let(:composer)           { Artist.new("Greg Graffin") }
  let(:artist)             { Artist.new("Bad Religion") }
  let(:album)              { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }

  let(:form) { AlbumForm.new(album) }

  it do
    form.validate("songs" => [{"title" => "Wrong"}, {"title" => "Brok"}])
    _(form.errors.messages).must_equal({:title=>{0=>["Invalid"]}})
  end 
end

Try replacing next if value[:id] with next if form.model.id as id isn't present in your params.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants