why revert "adding accessible option to allow for allowing mass assignments"?

Ryan,

Out of curiosity, do you have a "new task" link on the form which dynamically adds new fields using Javascript? Is it difficult to generate the auto-incrementing number with this?

I do have a "new task" link but it doesn't use javascript (I'm somewhat new to web development so I'm keeping this as simple as possible, which means no javascript).

Eloy's idea of using a timestamp for the id is, as you said, genius.

Re. Josh's comment on ordering, as long as you use a hash you're safe, right? You can order by the hash key -- I'm not missing anything? (perhaps around javascript drag-and-drop reordering?)

Re. approach 5 (in the gist), I prefer approach 4 because in your view you can say:   fields_for "tasks[#{position}]" instead of having to remember "update_tasks_params" and "create_tasks_params".

Like Eloy's implementation, in my project I specify whether or not I want to destroy records that are missing from the hash, by definitely agree that the best implementation would be to match what ActiveRecord already does for tasks= when taking an array of objects rather than a params hash -- which is, according to the docs: "Replaces the collection's content by deleting and adding objects as appropriate."

Re. Eloy's :reject_empty option: I never create records if all the attributes are blank (i.e. the user presses the "add another task" button but leaves the task completely blank). Is there really a use case for that? In fact, if a user deletes all the content from the fields of an existing task, my implementation would delete that record.

Cheers Dave.

Great to hear! I brought the issue up because the params parser can only parse 2 levels deep before it gets screwed up and generates the wrong hash (I guess this all depends on the hash structure that is ultimately decided on for nested mass-assignment).

I also agree that enabling this manually makes a lot of sense for security purposes.

Brad

Great to hear! I brought the issue up because the params parser can only parse 2 levels deep before it gets screwed up and generates the wrong hash (I guess this all depends on the hash structure that is ultimately decided on for nested mass-assignment).

Yes, that's why whatever implementation is chosen *must* use hashes rather than arrays.

Re. Josh's comment on ordering, as long as you use a hash you're safe, right? You can order by the hash key -- I'm not missing anything? (perhaps around javascript drag-and-drop reordering?)

Indeed. That's actually what he opted for with that comment, if I understood correctly.

Like Eloy's implementation, in my project I specify whether or not I want to destroy records that are missing from the hash, by a :destroy_missing option on the has_many declaration. But I definitely agree that the best implementation would be to match what ActiveRecord already does for tasks= when taking an array of objects rather than a params hash -- which is, according to the docs: "Replaces the collection's content by deleting and adding objects as appropriate."

Agreed, it seems to follow the principle of least surprise. However, I wonder if that might have to do with the fact that using a has_many writer method is usually not used in combination with mass assignment....?

I guess for me it just doesn't feel right if by default stuff will get deleted, where one might expect that you are simply updating the attributes. But this may very well just be me being "paranoia" :slight_smile: Comments?

Re. Eloy's :reject_empty option: I never create records if all the attributes are blank (i.e. the user presses the "add another task" button but leaves the task completely blank). Is there really a use case for that? In fact, if a user deletes all the content from the fields of an existing task, my implementation would delete that record.

Using the :reject_empty option as a default might indeed be sensible.

Deleting records for which we get a empty hash however is a different case. The problem is that you might not always be sending all attributes of a record. Thus assuming that a empty hash also means that all the attributes of a record are empty is a bit dangerous. There are ways to solve this of course, but that is not something I would like to have by default.

Eloy

Agreed, it seems to follow the principle of least surprise. However, I wonder if that might have to do with the fact that using a has_many writer method is usually not used in combination with
mass assignment....?

I guess for me it just doesn't feel right if by default stuff will get
deleted, where one might expect that you are simply updating the attributes. But this may very well just be me being "paranoia" :slight_smile: Comments?

You're right: "I submitted a form to edit one of my comments on a blog post, and all the other comments got deleted" is way more surprising than "when Post#comments= takes a params hash it acts differently than when it takes an array of Comment objects."

This is why I don't like overloading the comments= setter to handle hashes, but prefer having a comments_params= setter instead. The basic setter deals with models, the params setter is the convenience interface for controllers to use for multi-model form support. It's a much simpler implementation too.

Agreed, the setter method should have a different name than the existing "tasks=" method. The behavior is different enough to warrant its own method. Otherwise it will just be confusing on the implementation side and the API side. Is there any good reason for using the same setter method?

Ryan

Sorry I'm late to this discussion, I've been on holidays.

I've already spammed the list with this before, but I believe my plugin (which screws with UrlEncodedParameterParser) could solve some of the issues you guys are running into with this.

http://www.vector-seven.com/git/rails/plugins/form_collections.git/

It's not very well named, but it effectively uses Arrays instead of Hashes when numeric indices are used in the form. It also simplifies the implementation of UrlEncodedPairParser at the expense of slightly modified semantics in the parameter parsing (i.e. yes, it breaks a few tests -- some of which I'm convinced were not correct to begin with).

With such a patch in play, ordering issues would be resolved (thanks to the use of Arrays) and updates could be detected by effectively checking if the :id attribute is set on the nested form attributes. In the "Add Comment" case mentioned later in this discussion, I would assume one would be doing a many_assoc#<< rather than a many_assoc#= ...

The only thing really missing from the plugin is a way to handle sparse arrays. i.e. Assigning values only to indices 1, 200 and 999 of an array should not yield an array of 1000 elements, 997 of which are nil. This should be fairly trivial.

Cheers, Tom

Ryan Bates wrote:

Agreed, the setter method should have a different name than the existing "tasks=" method. The behavior is different enough to warrant its own method. Otherwise it will just be confusing on the implementation side and the API side. Is there any good reason for using the same setter method?

The reason I had used the association setter is because in the case of a has_one association things like fields_for would work out of the box and I only needed to create a special fields_for for a has_many association.

Eloy

I know this thread is crazy old…but I’m looking for a solution to submit one form with multiple instances of one model. I have a Responses model, and a user answers many questions on a page (like a quiz), and I want them to submit all their responses on one form. I had it working similar to Ryan’s approach 1, but the problem of multiple inputs with the same name in the HTML was causing trouble.

What is the current thinking on handling this in Rails 5? This has got to be a relatively common thing to want to do…

I recommend handling complex nested attributes like this with this gem https://github.com/trailblazer/reform

here you can find a good documenation

http://trailblazer.to/gems/reform/api.html