leastbad / optimism

The missing drop-in solution for realtime remote form validation in Rails.
MIT License
361 stars 42 forks source link

Handle reversed nested attribute collection #41

Closed gathuku closed 3 years ago

gathuku commented 3 years ago

When using rails accept_nested_attributes_for with dynamic items added by javascript, mostly we add items at the bottom. This means the first item will have child_index of 0 and the last will have the highest number. ie querySelect('.nested-fields').length.

If you change this behavior to add an item at the top level, meaning the last added item will be the topmost. The built params will look like this:-

"post" => {name"=>"New Post", "age"=>"2", "body"=>"", "consent"=>"0", "comments_attributes"=>{"2"=>{"id"=>"", "opinion"=>"comment 2"}, "0"=>{"id"=>"", "opinion"=>"comment 1"}}}

When rails Build the collection. I would expect rails to respect child_index on comments_attributes when building the collection, but this doesn't happen. In the below collection, I would expect a comment with child_index 0,(opinion: 'comment 1') to the first one.

@post.comments

#<ActiveRecord::Associations::CollectionProxy [#<Comment id: nil, post_id: nil, opinion: "comment 2", created_at: nil, updated_at: nil>, #<Comment id: nil, post_id: nil, opinion: "comment 1", created_at: nil, updated_at: nil>]>

Because optimism depends on these collections build by rails, there becomes a mismatch of errors to the wrong HTML selectors.

my solution

Provide a way to define attributes to be reversed. This will be defined if the user decides to use the last item first approach when building nested items.

broadcast_errors(model, params, reverse_attributes_for: [:comments])