Hi Peter and all,
You must be right that my double tag approach is working because it groups
the two inputs together. No matter how many combinations of inputs I tried,
I could not get delete to work with just one hidden input. I always had to
use pairs; one to define the id and the other to signify the delete. You
raised an excellent concern, though. Would this start failing if I had
multiple children to delete in one server request? Also what would happen
if there was a mix of inserts and deletes? Further testing showed odd
behavior. The only way I have been able to get this to work is with pairs
of hidden inputs as follows:
<!-- Add a booking -->
<input type="hidden" name="room[bookings_attributes][][id]"/>
<input type="hidden" value="11/18/2009" name="room[booking
s_attributes][][date]"/>
<!-- Delete a booking -->
<input type="hidden" value="15" name="room[bookings_attributes][][id]"/>
<input type="hidden" value="1" name="room[bookings_attributes][][_delete]"/>
<!-- Delete a booking -->
<input type="hidden" value="16" name="room[bookings_attributes][][id]"/>
<input type="hidden" value="1" name="room[bookings_attributes][][_delete]"/>
<!-- Add a booking -->
<input type="hidden" name="room[bookings_attributes][][id]"/>
<input type="hidden" value="01/22/2010" room="board[booking
s_attributes][][date]"/>
These get translated to parameters as follows:
Parameters:
{"commit"=>"Update Reservation!",
"authenticity_token"=>"blah",
"id"=>"1",
"room"=>
{"bookings_attributes"=>
[{"id"=>"", "date"=>"11/18/2009"},
{"_delete"=>"1", "id"=>"15"},
{"_delete"=>"1", "id"=>"16"},
{"id"=>"", "date"=>"01/22/2010"}
]
}
}
I think that herein lies the key to why this works this way. I wish I
understood it a little better, but what I'm able to deduce is that the
current implementation of nested attributes needs the child objects to be
presented in an array where each element of the array is a hash containing
child object attributes and optionally the delete flag.
Given that requirement, there seems to be a limitation on how the input tags
are parsed. The only way to get something on the right side of a '=>' in
the hashes is to put it in the 'value' attribute of the html input tag. For
example:
<input type="hidden" value="1" name="room[bookings_attributes][16][_delete]"
/>
gets parsed to {"booking_attributes" => {"16" => {"_delete" => "1"}}} The
documentation says that should be ok, but rails doesn't actually do the
deletion ... nor does it complain.
Anyway, that's a long story, but it's such an odd case that doesn't seem to
be deeply explored in blogs and writeups, so I thought I'd share it with
everyone.
Thanks,
--Jon
On Tue, Nov 3, 2009 at 1:25 AM, Peter Gumeson <[email protected]> wrote:
>
> Or possibly it's working because it groups the two inputs together
> since they both start with "room[bookings_attributes][]". Meaning
> additional bookings would need to define the PK in the name field
> anyway. That way seems more obvious to me anyway, especially if it
> works having just one input for delete.
>
> Peter
>
>
> On Nov 3, 12:10 am, Peter Gumeson <[email protected]> wrote:
> > Are you sure it's not just defaulting to 56 because it's the first
> > (and only) booking input field you have. It seems this would break if
> > you have more than one booking... because you would essentially be
> > duplicating the second input, which is ambiguous without something
> > tying it to the first input.
> >
> > And yes you are right about the value needing to eval true. I now
> > remember seeing the following pattern:
> >
> > <input name="room[booking_attributes][3][_delete]" type="hidden"
> value="0" />
> > <input name="room[booking_attribute][3][_delete]" type="checkbox"
> value="1" />
> >
> > So this would only delete booking 3 if the box was checked. But
> > again, this seems to indicate the id gets set in the name string
> > instead of the value. Have a look athttp://
> github.com/alloy/complex-form-examplesas this is where I have
> > seen this pattern being used.
> >
> > Also, be sure you are setting :allow_destroy => true on your
> > nested_attributes_for declaration.
> >
> > Peter
> >
> >
> >
> >
> >
> > On Mon, Nov 2, 2009 at 11:05 PM, Jonathan Christensen <[email protected]>
> wrote:
> > > Hey thanks Peter!
> >
> > > This set me on the right track. It turned out that I ended up needing
> two
> > > hidden input fields. One to specify the ID of the child object I
> wanted to
> > > delete, and the other to send the '_delete' command:
> >
> > >
> <input type="hidden" value="56" name="room[bookings_attributes][][id]"/>
> > > <input type="hidden" value="1"
> > > name="room[bookings_attributes][][_delete]"/>
> >
> > > When these are parametrized, rails receives the following:
> >
> > > Parameters: {"commit"=>"Update Reservation!",
> "authenticity_token"=>"blah",
> > > "id"=>"11", "room"=>{"bookings_attributes"=>[{"_delete"=>"1",
> "id"=>"56"}]}}
> >
> > > I was surprised to learn from some reading that setting _delete => 1 is
> > > required because it must be set to something that evaluates to true.
> >
> > > And finally, the desired SQL:
> > > DELETE FROM "bookings" WHERE "id" = 56
> >
> > > Thanks again. I may still end up going the ajax route, but at least
> now it
> > > won't be for lack of options.
> > > --Jon
> >
> > > On Mon, Nov 2, 2009 at 7:00 PM, Peter Gumeson <[email protected]>
> wrote:
> >
> > >> Hey Jon,
> >
> > >> It looks like you are missing the primary key of the record you are
> > >> trying to delete. In other words, I don't think the value attribute is
> > >> even used by rails when identifying the record to delete.
> >
> > >> I believe your input tag should look something like this:
> > >> <input type="hidden" name="room[bookings_attributes][1][_delete]"/>
> >
> > >> (where 1 is the PK of the booking)
> >
> > >> So you'll probably have to find a way to lookup the primary key of the
> > >> booking date that was clicked for deletion. You could print out a
> > >> javascript hash of booking dates mapped to their PKs, and remember to
> > >> update it whenever a booking is added/removed. Or you could do an ajax
> > >> call to get the PK.
> >
> > >> However, keep in mind that if you're hitting the server with ajax for
> > >> each lookup, it's probably just as easy to delete the booking while
> > >> you're there. It always seems I run into issues like this when using
> > >> nested attributes and usually just convert it to ajax in the end.
> >
> > >> Hope this helps.
> > >> Peter
> >
> > >> On Nov 2, 7:56 am, Jonathan Christensen <[email protected]> wrote:
> > >> > Hi all,
> >
> > >> > This question is about getting delete to work on nested models
> during an
> > >> > update on the parent object.
> >
> > >> > I'm using a jquery datepicker to allow users to add and remove
> multiple
> > >> > dates (bookings) from a parent object (room). Adding dates to the
> > >> > parent
> > >> > object is easy. The jquery datepicker gives me a function that gets
> > >> > called
> > >> > whenever the user clicks on a date. Within this function, I can
> build a
> > >> > hidden input that looks like this within the page:
> >
> > >> > <input type="hidden" value="12/04/2009" name="room
> > >> > [bookings_attributes][][date]"/>
> >
> > >> > Then within the controller, with the help of nested models, the call
> to
> > >> > @room.update_attributes(params[:room]) knows to create the bookings
> as
> > >> > well.
> >
> > >> > My question, is how can I build an input tag in the html that will
> tell
> > >> > the
> > >> > controller to remove an existing booking if the user unselects a
> > >> > previously
> > >> > saved booking from within the calendar?
> >
> > >> > if I build one like this:
> >
> > >> > <input type="hidden" value="12/12/2009" name="room
> > >> > [bookings_attributes][][_delete]"/>
> >
> > >> > then, the parameters get passed like this:
> >
> > >> > Parameters: {"commit"=>"Update Reservation",
> > >> > "authenticity_token"=>"blah",
> > >> > "id"=>"11",
> > >> > "room"=>{"bookings_attributes"=>[{"_delete"=>"12/12/2009"}]}}
> >
> > >> > And then the following sql happens:
> >
> > >> > SELECT "bookings".id FROM "bookings" WHERE ("bookings"."date" IS
> NULL
> > >> > AND
> > >> > "bookings".room_id = 11) LIMIT 1
> >
> > >> > Which isn't right. I'm thinking maybe I need two input tags? One
> to
> > >> > identify the booking that I'm removing and the other to tell the
> > >> > controller
> > >> > to delete it? Any help on how this should work would be
> appreciated. I
> > >> > could also do this the long way and just create separate and
> unrelated
> > >> > input
> > >> > tags and put the intelligence for deleting into my controller, but i
> > >> > feel
> > >> > like nested models should give me this for free...
> >
> > >> > Thanks in advance,
> > >> > --Jon
> >
> > --
> > Peter Gumeson
> > [email protected]
> >
>
--~--~---------~--~----~------------~-------~--~----~
SD Ruby mailing list
[email protected]
http://groups.google.com/group/sdruby
-~----------~----~----~----~------~----~------~--~---