-
Notifications
You must be signed in to change notification settings - Fork 21.6k
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 can be indexed with nested attributes #19686
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,31 @@ | ||
* Add option to index errors in nested attributes | ||
|
||
For models which have nested attributes, errors within those models will | ||
now be indexed if :index_errors is specified when defining a | ||
has_many relationship, or if its set in the global config. | ||
|
||
E.X. | ||
|
||
```ruby | ||
class Guitar < ActiveRecord::Base | ||
has_many :tuning_pegs | ||
accepts_nested_attributes_for :tuning_pegs | ||
end | ||
|
||
class TuningPeg < ActiveRecord::Base | ||
belongs_to :guitar | ||
validates_numericality_of :pitch | ||
end | ||
``` | ||
|
||
- Old style | ||
- `guitar.errors["tuning_pegs.pitch"] = ["is not a number"]` | ||
|
||
- New style (if defined globally, or set in has_many_relationship) | ||
- `guitar.errors["tuning_pegs[1].pitch"] = ["is not a number"]` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This example doesn't show either way to configure indexed errors. This is the place to spell it out. |
||
|
||
*Michael Probber and Terence Sun* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||
|
||
* Fixed a bug where uniqueness validations would error on out of range values, | ||
even if an validation should have prevented it from hitting the database. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -141,6 +141,8 @@ def self.valid_options | |
|
||
included do | ||
Associations::Builder::Association.extensions << AssociationBuilderExtension | ||
mattr_accessor :index_nested_attribute_errors, instance_writer: false | ||
self.index_nested_attribute_errors = false | ||
end | ||
|
||
module ClassMethods | ||
|
@@ -315,22 +317,26 @@ def validate_single_association(reflection) | |
def validate_collection_association(reflection) | ||
if association = association_instance_get(reflection.name) | ||
if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave]) | ||
records.each { |record| association_valid?(reflection, record) } | ||
records.each_with_index { |record, index| association_valid?(reflection, record, index) } | ||
end | ||
end | ||
end | ||
|
||
# Returns whether or not the association is valid and applies any errors to | ||
# the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt> | ||
# enabled records if they're marked_for_destruction? or destroyed. | ||
def association_valid?(reflection, record) | ||
def association_valid?(reflection, record, index=nil) | ||
return true if record.destroyed? || record.marked_for_destruction? | ||
|
||
validation_context = self.validation_context unless [:create, :update].include?(self.validation_context) | ||
unless valid = record.valid?(validation_context) | ||
if reflection.options[:autosave] | ||
record.errors.each do |attribute, message| | ||
attribute = "#{reflection.name}.#{attribute}" | ||
if index.nil? || (!reflection.options[:index_errors] && !ActiveRecord::Base.index_nested_attribute_errors) | ||
attribute = "#{reflection.name}.#{attribute}" | ||
else | ||
attribute = "#{reflection.name}[#{index}].#{attribute}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This branch is the same as the first, so I think we can improve this conditionals to have only two branches. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We originally had it as 2 branches, but the first branch looked excessively long. Should we still do 2 branches? |
||
end | ||
errors[attribute] << message | ||
errors[attribute].uniq! | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class Guitar < ActiveRecord::Base | ||
has_many :tuning_pegs, index_errors: true | ||
accepts_nested_attributes_for :tuning_pegs | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class TuningPeg < ActiveRecord::Base | ||
belongs_to :guitar | ||
validates_numericality_of :pitch | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo of
it's
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that is the correct way to spell
its
hereOn Mon, Oct 26, 2015, 5:20 PM Shunsuke Aida notifications@github.com
wrote:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's best you check its meaning 🤓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider a user reading this. Where would you find "global config?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its
indicates possession.it's
is a contraction forit is
.The latter seems to be the case here. If so,
it is
would be even better.