10

How can we fix the nested_attribute: _result_fields.html.erb so that when a user clicks "Delete" that it actually deletes it? Whereas now clicking it does nothing.

<%= f.text_field :result_value, class: 'form-control', placeholder: 'Enter Result' %>
<%= f.date_select :date_value, :order => [:month, :day, :year], :with_css_classes => true, :class => "date-select" %>
<%= f.check_box :bad %>
<%= link_to_remove_association f do %>
  Delete
<% end %>

stats has_many results

stats/_form

<div id="results">
  <%= f.fields_for :results do |result| %>
  <%= render 'result_fields', :f => result %>
  <% end %>
</div>

  <span class="label label-primary">
    <%= link_to_add_association f, :results do %>
    <span class="glyphicon glyphicon-plus"></span> Result
    <% end %>
  </span>

In stats_controller I have this as a params: results_attributes: [:id, :result_value, :date_value, :bad, :_destroy]

The models:

class Stat < ActiveRecord::Base
  has_many :results
  accepts_nested_attributes_for :results, :reject_if => :all_blank, :allow_destroy => true
end

class Result < ActiveRecord::Base
  belongs_to :stat
end

I'm using the cocoon gem.

Please let me know if you need further code or explanation. Thank you!

BY REQUEST

class StatsController < ApplicationController
  before_action :set_stat, only: [:show, :edit, :update, :destroy, :like]
  before_action :logged_in_user, only: [:create, :destroy]
  before_action :correct_user, only: [:edit, :update, :destroy]

  def index
    if params[:tag]
      @stats = Stat.tagged_with(params[:tag])
    else
      @stats = Stat.joins(:results).all
      @averaged_stats = current_user.stats.averaged
      @instance_stats = current_user.stats.instance
    end
  end

  def show
    @stat = Stat.find(params[:id])
    @commentable = @stat
    @comments = @commentable.comments
    @comment = Comment.new
    @notable = @stat
    @notes = @notable.notes
    @note = Note.new
    @correct_user = current_user.stats.find_by(id: params[:id])
  end

  def new
    @stat = current_user.stats.build 
  end

  def edit
  end

  def create
    @stat = current_user.stats.build(stat_params)
    if (params[:commit] == 'conceal')
      @stat.conceal = true
      @stat.save
      redirect_to @stat, notice: 'Stat was successfully created'
    elsif
      @stat.save
      track_activity @stat
      redirect_to @stat, notice: 'Stat was successfully created'
    else
      flash.now[:danger] = 'Required Fields: "Averaged or Instance", "Enter Action", "Enter Metric", and "+ Result"'
      render 'new'
    end
  end

  def update
    if @stat.update(stat_params)
      redirect_to stats_url, notice: 'Goal was successfully updated'
    else
      render action: 'edit'
  end
end

  def destroy
    @stat.destroy
    @result.destroy
    redirect_to stats_url
  end

  def like
    @stat = Stat.find(params[:id])
    @stat_like = current_user.stat_likes.build(stat: @stat)
    if @stat_like.save
      @stat.increment!(:likes)
      flash[:success] = 'Thanks for liking!'
    else
      flash[:error] = 'Two many likes'
    end  
      redirect_to(:back)
  end

  private
    def set_stat
      @stat = Stat.find(params[:id])
    end

    def correct_user
      @stat = current_user.stats.find_by(id: params[:id])
      redirect_to root_url, notice: "Not authorized to edit this stat" if @stat.nil?
    end

    def stat_params
      params.require(:stat).permit(:categories, :like, :action, :metric, :date, :comment, :private_submit, :tag_list, results_attributes: [:id, :result_value, :date_value, :bad, :_destroy])
    end
end

stat.js

$( document ).ready(function() {
  $('.date-format-switcher').click(function(event){
    event;
    if ($(this).attr('id') == 'stat_categories_instance') {
      $('.day').show();
     } else if ($(this).attr('id') == 'stat_categories_averaged') {
        $('.day').hide();
    }
})
  $('.add-form-padding').on('cocoon:after-insert', function(e, insertedItem) {
    if($('#stat_categories_instance').is(':checked')) {
      $('.day').show();
    } else {
        $('.day').hide();
    }
})
});
tereško
  • 58,060
  • 25
  • 98
  • 150
AnthonyGalli.com
  • 2,796
  • 5
  • 31
  • 80

2 Answers2

34

If the link_to_add_association works, the javascript is loaded correctly.

Still a bit confused about what is not working. If clicking the link_to_remove_association does not remove anything visibly from the page, you are missing the correct wrapper-class. By default it should be .nested-fields, but this can be overruled by specifying it explicitly (as documented ).

But if the items are visually removed, and you think it should be sent to the server immediately, then you misunderstand how cocoon works: you edit a form, which is only saved (sent to the server) when you submit the form. So the link_to_remove_association only visible removes the nested-child, and edits the contents of the form (sets the _destroy flag), so when saving/submitting the form, the nested child will be deleted.

nathanvda
  • 49,707
  • 13
  • 117
  • 139
3

Maybe the problem is that you didn't include the javascript that cames with the gem in order to invoke the links as expected, are you using ruby on rails 3 or 4? That's really important when asking questions in rails, since they differ a lot

Check your application.js file that is located in app/assets/application.js and make sure that you added this line:

//= require cocoon

if you already added the assets, check the source code of the page and please confirm that the javascript defined for cocoon is being loaded in the page

if that is already done, please update the question and add the rails log that you see when you click on the link and also let me know which version of rails you are using

rorra
  • 9,593
  • 3
  • 39
  • 61
  • Thanks Rorra! `//= require cocoon` is there. There is no rails log when I click on the link. Nothing happens. Maybe the javascript I added is creating the problem? I added it to the question for your reference. Thanks again :-] – AnthonyGalli.com Jun 21 '15 at 20:57
  • @AnthonyGalli.com Based on your description I believe the issue is regarding the javascript on the client side, because no request is made on the server. What cocoon does when you click on the link, it hides the current option, and on the background there is a hidden check field named _destroy which is marked (that if the field already exists in the db, if the field was just added then the div is just hidden). Can you please let me know if the field was already persisted on db, and if when you click on the link, it hides the div and/or it marks the hidden field? – rorra Jun 21 '15 at 21:03
  • also please check the javascript console of the browser and make sure there is not any js exception, and lastly, remove all js but the cocoon js just to double check if some other js that is being loaded is making conflicts with cocoon, although its really hard to create some custom code that cause conflicts to cocoon, most probably there is some other js code causing an error and avoiding cocoon to load/execute its code. – rorra Jun 21 '15 at 21:05
  • for future readers, make sure you're putting `//= require cocoon` after `//= require jquery` in your application.js or else it won't work. – rosalynnas Jul 24 '18 at 23:23