shultz
shultz

Reputation: 2693

Destroy nested fields in rails 4

Good day,

I'm trying to create simple form with list of links in RoR 4 which can be edited and removed.

I've allowed "destroy" at the main post model file controller->posts.rb

class Post < ActiveRecord::Base
has_many(:links, :dependent => :destroy)

accepts_nested_attributes_for :links,    :reject_if => lambda { |a| a[:link].blank? },   :allow_destroy => true

and I'm accepting the parameters for destroy at the create and update controller

    def create
    @new_post = Post.new(params[:post].permit(:title, :body, :tag_list,     links_attributes:[:link, :_destroy]))

    if @new_post.save
        redirect_to posts_path, :notice =>"Saved!"
    else
        render new
    end
end

def update
    @post_to_update = Post.find(params[:id])

    if @post_to_update.update(params[:post].permit(:title, :body, :tag_list,    links_attributes:[:link, :_destroy]))
        redirect_to posts_path, :notice =>"Updated!"
    else
        render edit
    end
end

I'm using jQuery to remove the link field and set its destroy value as "true"

<h1> Edit post </h1>
<%= form_for @post_to_edit do |f|%>
    Title <%= f.text_field :title %> </br>
    Body <%= f.text_area :body %> </br>
    <%= f.fields_for :links do |b| %>
    <li class = "enter_link">
        <%= b.text_field :link %>
        <%= b.hidden_field :_destroy %>
        <%= link_to_function "Remove", "remove_fields(this)" %></br>
    </li>
    <% end %>
    Tags <%= f.text_field :tag_list %>
    <%= f.submit "Update that bitch!" %>
<% end %>

Javascript

function remove_fields(link) {
    $(link).prev("input[type=hidden]").val("true");
    $(link).closest(".enter_link").hide();

}

And here's the problem: suppose I've got a list of 3 links

"link 1"
"link 2"
"link 3"

And I wish to edit that list by removing link number 2 and 3. once I press update the destroy parameters is passed on to the controller, but it wont delete the original lines.

Now I'll get the following list

"link 1"
"link 2"
"link 3"
**"link 1" (again, after removing link number 2 and 3)**

As always, your help is appreciated.

Upvotes: 3

Views: 4882

Answers (2)

mtkcs
mtkcs

Reputation: 1716

change this:

def update
    @post_to_update = Post.find(params[:id])

    if @post_to_update.update(params[:post].permit(:title, :body, :tag_list,    links_attributes:[:link, :_destroy]))
        redirect_to posts_path, :notice =>"Updated!"
    else
        render edit
    end
end

to this:

def update
    @post_to_update = Post.find(params[:id])

    if @post_to_update.update(
                         params[:post].permit(:title, :body, :tag_list, 
                         ## add `:id` to this one   
                         links_attributes:[:id, :link, :_destroy])
                         ##
                         )
        redirect_to posts_path, :notice =>"Updated!"
    else
        render edit
    end
end

you have to permit the id in your links_attributes params, so that the records don't get duplicated and for _destroy to work

Upvotes: 2

Dileet
Dileet

Reputation: 2064

Let me make your life easier and recommend this gem called Cocoon (https://github.com/nathanvda/cocoon)

It creates simple nested forms.

Simply paste this code into your Post form view.

  f.fields_for :links do |link|
  render 'link_fields', :f => link
  link_to_add_association 'add link', f, :tasks

With cocoon a partial is needed for the nested form, so create a file called _link_fields.html.erb

and inside make sure you place everything inside a div. Their documentation isnt clear on this, but from experience I do know its required.

<div class="nested-fields">
f.label :link
f.text_field :link
link_to_remove_association "remove link", f
</div>

And thats it!

Upvotes: 2

Related Questions