Skip to content

Errors can be indexed with nested attributes#19686

Merged
sgrif merged 1 commit into
rails:masterfrom
tsun1215:index_errors
Oct 26, 2015
Merged

Errors can be indexed with nested attributes#19686
sgrif merged 1 commit into
rails:masterfrom
tsun1215:index_errors

Conversation

@mprobber

@mprobber mprobber commented Apr 7, 2015

Copy link
Copy Markdown
Contributor

accepts_nested_attributes_for can now take index_errors: true as an
option. When this is enabled, errors for nested models will be
returned alongside an index, as opposed to just the nested model name.
This option can also be enabled globally in a configuration file.

@tsun1215
#8638

Comment thread activerecord/test/cases/helper.rb Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change, but isn't it indices?

Comment thread activerecord/CHANGELOG.md Outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use || and ! here to be in line with our style guide 😄

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. We'll update once we figured out how we should break the conditional up (see above).

@mprobber mprobber force-pushed the index_errors branch 5 times, most recently from 695b20b to b8cbac1 Compare April 8, 2015 22:06
`has_many` can now take `index_errors: true` as an
option.  When this is enabled, errors for nested models will be
returned alongside an index, as opposed to just the nested model name.
This option can also be enabled (or disabled) globally through
`ActiveRecord::Base.index_nested_attribute_errors`

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"]`

[Michael Probber, Terence Sun]
@sgrif sgrif merged commit 21e448b into rails:master Oct 26, 2015
sgrif added a commit that referenced this pull request Oct 26, 2015
Errors can be indexed with nested attributes

Close #8638
Comment thread activerecord/CHANGELOG.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo of it's?

Copy link
Copy Markdown
Contributor

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 here

On Mon, Oct 26, 2015, 5:20 PM Shunsuke Aida notifications@github.com
wrote:

In activerecord/CHANGELOG.md
#19686 (comment):

@@ -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.

typo of it's?


Reply to this email directly or view it on GitHub
https://github.com/rails/rails/pull/19686/files#r43067124.

Copy link
Copy Markdown
Member

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 🤓

Copy link
Copy Markdown
Member

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?"

Copy link
Copy Markdown
Contributor

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 for it is.
The latter seems to be the case here. If so, it is would be even better.

@bogdan

bogdan commented Oct 27, 2015

Copy link
Copy Markdown
Contributor

Excellent stuff guys!

@rweng

rweng commented Oct 31, 2015

Copy link
Copy Markdown

pulled it in on top of 4.2.4 and it works like a charm. Would love to see this change being in 4.2.5 so I can discard my fork :)

@kaspth

kaspth commented Oct 31, 2015

Copy link
Copy Markdown
Contributor

Sorry, we don't backport features to patch releases. This'll be in Rails 5.

@uberllama

Copy link
Copy Markdown
Contributor

Long overdue. Thanks for your effort. 🏁

bbuchalter pushed a commit to TommyJohnWear/solidus that referenced this pull request Nov 18, 2016
  * Using an instance variable allows JS populate operations to have
    access to the @order from within the rendered .js.erb files

  * Assign all line_item errors to the order's base

  * Allow to respond to JS requests for `#populate` and `#update` actions.
    It is left for the developer to actually implement the `js.erb` views

To consider / TODO:

  - to avoid the whole rescue operation, and manually assigning line item
    errors to the order, we'd need to do to be doing `order.save`
    instead of `line_item.save!` in [`OrderContents`](https://github.com/solidusio/solidus/blob/master/core/app/models/spree/order_contents.rb#L151)

  -> That would have the effect to "automatically" assign the line item
     errors on the order in the form: `line_items.quantity` in Rails 4.x
     and "line_items[0].quantity" in Rails 5

  More info:
  - rails/rails#8638
  - rails/rails#19686
kdiogenes added a commit to kdiogenes/active_type that referenced this pull request Feb 7, 2017
@kdiogenes

kdiogenes commented Feb 8, 2017

Copy link
Copy Markdown

I can't find a way to parse my errors messages:

errors = {
  "categories[0].listener_deadline_values[0].value": ["can't be blank"],
  "categories[0].listener_deadline_values[0].deadline": ["can't be blank"],
  "categories[0].name": ["can't be blank"],
  "categories[1].listener_deadline_values[0].value": ["can't be blank"],
  "categories[1].listener_deadline_values[0].deadline": ["can't be blank"],
  "categories[1].name": ["can't be blank"],
  "categories[2].listener_deadline_values[0].value": ["can't be blank"],
  "categories[2].listener_deadline_values[0].deadline": ["can't be blank"],
  "categories[2].name": ["can't be blank"]
}

I would expect to be able to access these errors like errors.categories[2].name

How do you parse it? I discovered how: https://medium.com/@kdiogenes/giving-super-powers-to-rails-nested-forms-with-vue-js-part-2-acee4a3ee43d

@tommyalvarez

Copy link
Copy Markdown

Is there a way to index by another criteria @mprobber ? Like the ID of the nested model if it's not a new record? This is because i can't figure a way when using rails 5 api to map errors into several nested children which some of them can have errors while others not, therefore indexes won't match one on one. Or is there another clever solution to handle this situation?

@vidurangaw

Copy link
Copy Markdown

@tommyalvarez
I'm having the exact issue you've faced. Were you able to find a solution?

@tommyalvarez

Copy link
Copy Markdown

@vidurangaw i ended up writing my own custom NestedErrorSerializer (i was using active model serializer with json-api adapter). This way i was able to return the errors the way i wanted, respeting json-api format. Thought it would take me a lot of time but it wasn't that hard at all. Here is the implementation i made:

module NestedErrorSerializer
  # object is the object to serialize, relationships an array of symbols with the relationships of the object
  def self.serialize(object, relationships)
    errors = object.errors.messages.map do |field, errors|
      errors.map do |error_message|
        {
          source: {pointer: "/data/attributes/#{field}"},
          detail: error_message
        }
      end
    end
    relationships.each do |relationship|
      object.send(relationship).each_with_index do |child, index|
        errors << child.errors.messages.map do |field, errors|
          errors.map do |error_message|
            {
              source: {pointer: "/data/attributes/#{child.model_name.plural}[#{index}].#{field}"},
              detail: error_message
            }
          end
        end
      end
    end if relationships.present?
    errors.flatten
  end
end

Then in the controller i used them like:

render json: {errors: NestedErrorSerializer.serialize(@product, [:consumables])}, status: :unprocessable_entity

@vidurangaw

Copy link
Copy Markdown

@tommyalvarez
Thanks for the quick response. I'll try this

@aruprakshit

Copy link
Copy Markdown

Why this option is not mentioned in the official doc ?

@dhyegocalota

Copy link
Copy Markdown

I've created a gem (active_record-nested_error_indexer) to monkey patch these changes to Rails 4 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.