How is it possible to use a callback and which one to avoid the destroying of the last association. For example, there are 3 following models: #timesheet.rb class Timesheet < ActiveRecord::Base has_many :activities, dependent: :destroy has_many :time_entries, through: :activities accepts_nested_attributes_for :activities, allow_destroy: true end #activity.rb class Activity < ActiveRecord::Base has_many :time_entries, order: :workdate, dependent: :destroy accepts_nested_attributes_for :time_entries, allow_destroy: true, reject_if: proc { |a| a[:worktime].blank? } end #time_entry.rb class TimeEntry < ActiveRecord::Base belongs_to :activity validates :worktime, presence: true, inclusion: { in: [0.5, 1] } end Every timesheet is created for 7 days (tile_entries) for one activity in the the same form. To delete I use the technic with jQuery explained at Railscats: #add_remove_fields.js function remove_fields(link) { $(link).prev("input[type=hidden]").val("1"); $(link).closest(".fields").hide(); } function add_fields(link, association, content) { var new_id = new Date().getTime(); var regexp = new RegExp("new_" + association, "g"); $(link).parent().before(content.replace(regexp, new_id)); } #application_helper.rb def link_to_remove_fields(name, f) f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)") end def link_to_add_fields(name, f, association, timesheet) ... end I tried several ways with after_destroy hook, - it didn''t work. Any idea ? Thanks and regards. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/NuK71fNT6hkJ. For more options, visit https://groups.google.com/groups/opt_out.
So still no idea how to avoid the destroy of the last association. I do all the processing in the ''update '' action of TimesheetsController. I tried with ''after_update'' hook in the Timsheet model as follows: #timesheet.rb class Timesheet < ActiveRecord::Base accepts_nested_attributes_for :activities, allow_destroy: true after_update :check_an_activity_present private def check_an_activity_present raise "You should have at least ONE activity present" if activities.empty? end end An I put the update_attributes in the begin/rescue block in the controller: #timesheets_controller.rb class TimesheetsController < ApplicationController def update begin @timesheet = current_user.timesheets.find(params[:id]) if @timesheet.update_attributes(params[:timesheet]) flash[:success] = ''Timesheet updated sucessfully'' redirect_to @timesheet else load_entries render ''edit'' end rescue Exception => e flash.now[:error] = e.message @entries = @timesheet.time_entries render ''edit'' end private def load_entries @entries = @timesheet.build_and_sort_time_entries end end end The problem is that the activity with corresponding time entries collection is not destroyed even if I added a new activity with corresponding time entries. So after the update executed, I have 2 activities saved with corresponding time entries instad of having just the ONLY one, entered just after the destroying the previous one. Any idea? Thank you. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/x0Aey747JSkJ. For more options, visit https://groups.google.com/groups/opt_out.
Finally, after_update callback works as needed, te problem was in the new fields_for generation. The below is the correct and updated version: #timesheet.rb> class Timesheet < ActiveRecord::Base > has_many :activities, dependent: :destroy > has_many :time_entries, through: :activities > accepts_nested_attributes_for :activities, allow_destroy: true > end > > #activity.rb > class Activity < ActiveRecord::Base > has_many :time_entries, order: :workdate, dependent: :destroy > accepts_nested_attributes_for :time_entries, allow_destroy: true, > reject_if: proc { |a| a[:worktime].blank? } >validate :one_time_entry_present private def one_time_entry_present errors[:base] << "At least one entry should be entered" if time_entries.empty? end> end > > #time_entry.rb > class TimeEntry < ActiveRecord::Base > belongs_to :activity > validates :worktime, presence: true, inclusion: { in: [0.5, 1] } > end > > Every timesheet is created for 7 days (tile_entries) for one activity in > the the same form. To delete I use the technic with jQuery explained at > Railscats: > #add_remove_fields.js > > function remove_fields(link) { > $(link).prev("input[type=hidden]").val("1"); > $(link).closest(''table'').find("tr.entry_header").hide(); > $(link).closest(".fields").hide(); > } > > function add_fields(link, association_id, content) { > var new_id = new Date().getTime(); > var regexp = new RegExp(association_id, "g"); > $(link).parent().before(content.replace(regexp, new_id)); > } > > #application_helper.rb > > def link_to_remove_fields(name, f) > f.hidden_field(:_destroy) + link_to_function(name, > "remove_fields(this)") > end > > def link_to_add_fields(name, f, association, timesheet) > new_object = f.object.send(association).klass.new > id = new_object.object_id > timesheet.create_activity_days(new_object) > > fields = f.fields_for(association, new_object, child_index: id) do > |builder| > render(association.to_s.singularize + "_fields", f: builder) > end > > > link_to_function(name, "add_fields(this, \"#{id}\", > \"#{escape_javascript(fields)}\")") > end >#timesheets_controller.rb def update begin @timesheet = current_user.timesheets.find(params[:id]) if @timesheet.update_attributes(params[:timesheet]) flash[:success] = ''Timesheet updated sucessfully'' redirect_to @timesheet else load_entries render ''edit'' end rescue Exception => e flash[:error] = e.message redirect_to edit_timesheet_path(@timesheet) end end Hope this helps. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/SPqrx4OMJIsJ. For more options, visit https://groups.google.com/groups/opt_out.