rails: index_errors does not consider indexes of correct existing sub records
Steps to reproduce
Updating existing record with accept_nested_attributes_for with existing sub-records. (Order - Entries), with index_errors: true. So, i have existing Order, with 2 existing entries, and try to update it with nested attributes
Expected behavior
Same indexes all times
Actual behavior
If im not changing entry_1, and change entry_2(with incorrect attributes) i got this response:
entries[0].title: ['some errors']
If im changing entry_1(correct attributes) and change entry_2(incorrect attributes) i got response
entries[1].title: ['some errors']
System configuration
Rails 5.0.0.beta3 ruby 2.2.3
About this issue
- Original URL
- State: open
- Created 8 years ago
- Reactions: 4
- Comments: 24 (8 by maintainers)
Commits related to this issue
- Fix validation error message for autosave association Fixes #24390 — committed to tijwelch/rails by tijwelch 8 years ago
- Add index_errors: :nested_attributes_order mode which respects reject_if and is in nested_attributes order. When in default index_errors:true mode, fix #24390 and return index based on full associat... — committed to lulalala/rails by lulalala a year ago
- Add index_errors: :nested_attributes_order mode which respects reject_if and is in nested_attributes order. When in default index_errors:true mode, fix #24390 and return index based on full associat... — committed to lulalala/rails by lulalala a year ago
I just encountered this issue too. I’m a big fan of nested attributes and was surprised to see that something was broken and has not been fixed for 4 years.
I tried the monkey patch above, changing
associated_records_to_validate_or_save
to return all records, but it was breaking my specs: some callbacks on nested records were called when they should not.So I tried to fix it myself with another approach. I’m not very familiar with the existing code so this might be a wrong approach too but here it is.
https://github.com/rails/rails/blob/4174d04f5bfaa451e150b8f97d6050dcfc51233d/activerecord/lib/active_record/autosave_association.rb#L337
The (wrong) index is created here: the
records
array is created viaassociated_records_to_validate_or_save
which returns the subset of records of the association which have changed. Then it iterates witheach_with_index
, which provides a “relative” index (we want an “absolute” index).So my solution is to replace this index with the “absolute” index. First I get all the records of the association (whether or not it changed):
all_records = association.target.find_all
Then for each record (each_with_index
is not required anymore), I get the “absolute” index withindex = all_records.find_index(record)
and provide it toassociation_valid?
.Here is the full monkey patch:
With this, my specs are good and the right index is returned. It looks like the
index
param is not used anywhere else but to generate errors index.I will try to submit a PR to get reviews from other contributors and eventually get this in Rails 🙂
For those who don’t want to monkey patch, I have implemented a hack to overcome this in one of my projects.
The idea is frontend needs to send a field (in my case “index”) and backend will override the rails index with what was sent from the frontend.
Code looks something like this:
I made two concerns as the code was being used in multiple models.
This below concern is to reindex the errors. This needs to be included in parent models.
This might not be the best solution but it works fine for my case.
As @zhufenggood mentioned, the error message is using the index of items that pass
changed_for_autosave?
, which in the case of the provided test is an array of one item so the index of 0 is used.Changing the method
associated_records_to_validate_or_save
(line 282) to return the full association.target array instead of only the items that passchanged_for_autosave?
gets the provided test to pass.https://github.com/rails/rails/blob/master/activerecord/lib/active_record/autosave_association.rb#L282
Updated method:
I have added this commit to my local branch and the ActiveRecord tests are still passing.
Happy to help out however I can. Is opening a PR with this commit the correct next step? Sorry, just getting into contributing here.
Thanks! You saved my life.
I can not imagine it’s near 2021, this bug still exist in RAILS6.
And
associated_records_to_validate_or_save
fixing method gave me a lot BUGs in after_save callbacks.Your patch works pretty fine for me!
Hi everyone, we in GitLab faced this issue and have created a new fix https://github.com/rails/rails/pull/48727. It should fix the original issue, while addressing
reject_if
by offering a new indexing mode. I would like to invite you to try it out and see if there is anything that I’ve overlooked. Thanks!I rewrote @AkshayGoyal022 reindex_nested_error method to work in Rails 6. See how to use it in his comment here: https://github.com/rails/rails/issues/24390#issuecomment-483610929
Also a small update to append_index_to_errors to clear a deprecation warning
In your pull request, could you please add the index_errors option to the documentation of the has_many association, and may be refer to it in the accepts_nested_attributes_for method? The option is nowhere documented accept for the Rails 5.0 update readme. Would be great!
@maclover7 I am willing to give this a try
Yep, this definitely looks like a bug to me. Would you be willing to investigate, and open up a pull request with a fix?