Re: RFC: Improving the rack parameter normalization

Allen
Sun, 09 Aug 2009 02:06:11 -0000

Unless I''m missing something, why wouldn''t you just use hidden
fields
that indicate the order?

On Aug 6, 11:06 pm, andy <andyrlo...@gmail.com>
wrote:
> I have struggled much of the day today to do something that on the
> surface seems like it should be a piece of cake. But either it''s
not,
> or I''m too dense to see the easy way to do it.
>
> I''m leaning toward modifying the rack parameter parser to (a) make
it
> far cleaner and more intelligible than it currently is (including
> documenting exactly what it does!), and (b) make it easy to do what
> I''m after. I think I can do this in a mostly backward-compatible
> fashion, and could provide a compatibility mode if needed for anyone
> who needs the old behavior.
>
> I''d appreciate any feedback the experts may have before I embark
on
> this.
>
> Here''s a simplified version of what I''m trying to do that
ended up
> being (I think) impossible without resorting to some javascript that
> really should not be required:
>
> Say I''ve got a nested model structure that looks like this:
>
> class Project < ActiveRecord::Base
>   has_many :tasks
>   accepts_nested_parameters_for :tasks
> end
>
> class Task < ActiveRecord::Base
>   belongs_to :project
> end
>
> I''d like to be able create an edit form for :project that includes
a
> dynamically varying list of :task subforms. I''ll have a delete
button
> next to each :task subform, and an "Add a Task" button at the
bottom
> of the last. All fairly standard and not very hard, especially with
> the new accepts_nested_parameters_for feature.
>
> But now here''s the kicker: I also want to use the
"sortable_element"
> helper so that the user can reorder the tasks - including newly added
> tasks - within the project. In order to save the final ordering, this
> means I need to be able to detect, from the request parameters, the
> order that the :task subforms appeared in the overall form at the time
> it was submitted. This should be easy, because browsers are required
> to send form parameters in the order in which they appear at the time
> of submission, and sortable_element works by physically reordering the
> subforms in the overall DOM structure.
>
> The problem is that rack loses this ordering information, and I''m
> pretty much convinced that it can''t be made to keep it. You can
ALMOST
> get this to work by specifying :index=>'''' and
:child_index=>'''' in all
> your fields_for calls. But this results in illegal HTML (strictly
> speaking, though it works, at least in the browser I''ve tried),
and
> it''s also slightly risky. The illegal part comes from the fact
that
> you''ll end up with multiple input elements in your form that have
the
> same id value. E.g. a text field for task ''name'' would
appear in
> every :task subform, and in each appearance it would carry the same id
> value.  And not only would that be illegal, it would also make it
> impossible to have per-subform radio button groups. The radio button
> input elements would all have the same name across all subforms, so
> they''d all be linked, rather than only within a subform.
>
> Even without those problems, the strategy is dangerous because of the
> way rack detects when it''s time to start a new hash, rather than
> continuing to fill a current hash. This comes into play for a
> parameter with a name like
''project[tasks_attributes][][name]''.  The
> the empty brackets call for an array of hashes at that point in the
> structure, and rack will look at whether ''name'' appears
as a key in
> the current last element of that array. If so, it opens up a new
> element in the array, otherwise it adds to the current last element.
>
> This mechanism will fail if not all your subforms offer the same set
> of fields. E.g you might have separate buttons for "add quick
task"
> and "add task," both of which add the same sort of object, but
"add
> quick task" provides an abbreviated form for easier entry.
You''d have
> to add the other fields as hidden fields in the abbreviated subform in
> order to be safe, and it''d probably be a hellish debugging
exercise to
> figure that out!
>
> OK, so here''s my idea:
>
> 1. When "[]" appears in a parameter name it always indicates an
array
> at that point in the structure. What fallows goes into a new element
> at the end of the array, using logic equivalent to what is currently
> provided by rack.
> 2. When "[.index]" appears, what follows will be be added to the
hash
> that is the current last element of the array. The leading dot
> prevents this index from itself being a hash key in what would then
> have to be a containing hash, rather than a containing array, so
> ordering of the substructures is preserved.
> 4. When "[+index]"  appears, a new hash is added to the end of
the
> array, and what follows goes into that hash.
> 5. When [index] appears in a parameter name (without leading dot or
> plus), the index is treated as a hash key for what follows same as
> current behavior.
>
> Here''s an example:
>
>    project[title]=''My Project''
>    project[tasks_attributes][+0][id]=1
>    project[tasks_attributes][.0][name]=Sleep
>    project[tasks_attributes][+1][id]=5
>    project[tasks_attributes][.1][id]=Sleep more
>    project[id]=3
>
> The params structure would look like this:
>    {:title=>"My Project", :id=>"3",
>        :tasks_attributes=>[{:id=>"1",
:name=>"Sleep"},
> {:id=>"5", :name=>"Sleep more"}]
>    }
>
> The current rake parameter processor would yield (assuming dots and
> pluses are removed from the above):
>    {:title=>"My Project, :id=>"3".
>        :tasks_attributes=>{"1"=>{:id=>"5",
:name=>"Sleep more"}, "0"=>
> {:id=>"1", :name=>"Sleep"}}
>    }
>
> With the new structure it would be simple matter for the controller to
> take a pass through params[:project][:tasks_attributes] and
> assign :position values for the benefit of acts_as_list in order to
> retain the final subform ordering. With the current structure, one
> would need to use a javascript callback before submit to add those
> values to the DOM, or AJAX calls to update positions every time
> something gets reordered. Neither would be all that difficult, but
> it''s infuriating, all the required information is already
available
> for free in the raw form submission.
>
> To make this really work well, the form helpers would also need to be
> modified to make use of the enhanced naming scheme. If I do this, my
> goal will be to do both the enhanced rack parameter parser and the
> form helper modifications to take advantage.
>
> Thanks for any comments or recommendations.
>
> -andy