nested_form gem add works but remove fails…why?

2019-06-23 18:01发布

I'm using the madebydna version of Ryan Bates' nested_form gem from GitHub (can be found at https://github.com/madebydna/nested_form). I'm using the forked version for jQuery support as opposed to Prototype.

UPDATE: Check the bottom of the page for an update to this question.

EDIT:

I'm using: RoR v3.0.5, jQuery v1.4.3, Ruby v1.9.2

END EDIT

EDIT: It appears the current structure of the pictures_attributes parameter passed along to the server is causing an issue, at least from what I've seen on other websites. The currently sent structure is as follows:

"pictures_attributes"=>{"0"=>{"_destroy"=>"1", "id"=>"5"}}

All other sites I've seen, the pictures_attributes error had the following structure:

"pictures_attributes"=>[{"_destroy"=>"1", "id"=>"5"}]

I'm not sure how to alter my code to make it so the latter occurs, rather than the former. Thoughts?

END EDIT

I followed the directions to a T, the add link works great for adding nested models, but remove fails. In otherwords, I can add multiple fields for a particular model, and those models get created and saved when I submit the form, but when I go to edit the same record again and go to remove the nested models which I just created, they fail to be removed from the associated record.

Here's the nested_form.js script that gets generated after installing the nested_form gem. Forgive but I created a Pastie and reduced it: http://bit.ly/ge5BO7

Here is the pertinent model code:

has_many :pictures, :as => :imageable, :dependent => :destroy
accepts_nested_attributes_for :pictures, :allow_destroy => true, :reject_if => lambda { |a| a[:photo].blank? }

Here is the view code (in the _form.html.erb partial):

<div id="picture_fields">
<% f.fields_for :pictures do |pics| %>
  <div class="field">
<%= pics.label :photo, "Photo" %>
<%= pics.file_field :photo %>
<%= pics.link_to_remove "Remove Photo" %>
  </div>
<% end %>
<p>
  <%= f.link_to_add "Add Photo", :pictures %>
</p>

Here's the generated HTML for one field:

<div class="fields">
    <div class="field">
    <label for="equipment_pictures_attributes_0_photo">Photo</label>
    <input id="equipment_pictures_attributes_0_photo" name="equipment[pictures_attributes][0][photo]" type="file">
    <input id="equipment_pictures_attributes_0__destroy" name="equipment[pictures_attributes][0][_destroy]" type="hidden" value="false">
        <a href="javascript:void(0)" class="remove_nested_fields">Remove Photo</a>
    </div>
    <input id="equipment_pictures_attributes_0_id" name="equipment[pictures_attributes][0][id]" type="hidden" value="5">
</div>

And here's the log entry that gets generated when submitting the form:

Started POST "/equipment/494882120" for <ipadd deleted> at 2011-03-24 13:04:18 -0400
  Processing by EquipmentController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"98/R6EYCAFd6HwBjMV6bhnfRo6cT7NqPZ9fJ/VEOKKE=", "equipment"=>{"location_id"=>"", "model"=>"fasdf", "serial_number"=>"", "unh_id"=>"", "doc_id"=>"", "purchase_price"=>"", "date_acquired(1i)"=>"2011", "date_acquired(2i)"=>"3", "date_acquired(3i)"=>"24", "comment"=>"", "vendor_id"=>"", "new_vendor_name"=>"", "department_id"=>"320903175", "new_department_name"=>"", "activity_id"=>"", "new_activity_code"=>"", "condition_id"=>"746868371", "new_condition_name"=>"", "pictures_attributes"=>{"0"=>{"_destroy"=>"1", "id"=>"5"}}}, "commit"=>"Update Equipment", "id"=>"494882120"}
  Equipment Load (0.7ms)  SELECT "equipment".* FROM "equipment" WHERE "equipment"."id" = 494882120 LIMIT 1
  Picture Load (0.4ms)  SELECT "pictures".* FROM "pictures" WHERE "pictures"."id" IN (5) AND ("pictures".imageable_id = 494882120 AND "pictures".imageable_type = 'Equipment')
DEPRECATION WARNING: Overwriting validate in your models has been deprecated, please use Base#validate :method_name instead. (called from block in update at /opt/intranet3-dev/app/controllers/equipment_controller.rb:63)
  Department Load (0.1ms)  SELECT "departments".* FROM "departments" WHERE "departments"."id" = 320903175 LIMIT 1
  Condition Load (0.1ms)  SELECT "conditions".* FROM "conditions" WHERE "conditions"."id" = 746868371 LIMIT 1

Now, as far as I'm concerned I'm covering all of my bases with allowing the nested objects to be destroyed when _destroy => '1' is encountered in the submitted parameters. However, the object is clearly not being destroyed. Is there an error in the way the parameters are being submitted to the server?

Hopefully someone with a keener eye than I will see some glaring error. Help!

UPDATE:

Okay, I've managed to resolve the problem by taking out the :reject_if clause from my accepts_nested_attributes_for statement. This is a fringe case in the event you have an upload file form, and I dare call it a bug.

In my case I was able to attach photos to my Equipment model, and when editing it would render the form such that the file field was blank (which is what's supposed to happen) for every photo I have attached to my record. After plugging away at this thing for hours, I pondered if the :reject_if clause was causing the controller action to ignore the nested record entirely, even though I told it to destroy the record. Well, it does.

If you have a :reject_if clause, coupled with a :allow_destroy => true, and if the :reject_if evaluates to true YOUR RECORD WILL NOT BE DESTROYED NO MATTER WHAT

I'm currently trying to hack out a method for retaining my :reject_if functionality.

Cheers, Les.

1条回答
太酷不给撩
2楼-- · 2019-06-23 18:39

The problem is that the state of the nested record, when submitted, is causing the :reject_if clause in the accepts_nested_attributes_for statement to evaluate to true, thus telling the controller to skip over it and perform no action on it. Hence, the nested record is not destroyed since no action is performed on it.

查看更多
登录 后发表回答