Home > Back-end >  Rails: discard child record before saving
Rails: discard child record before saving

Time:08-12

I'm trying to discard an associated record before its parent is saved in a Rails callback if a condition is met. Doing a throw :abort doesn't stop the record from saving. Am I doing something wrong?

class Document < ApplicationRecord 
  has_many :frames, as: :parent, dependent: :destroy
  has_many :frame_variables, through: :frames, dependent: :destroy

  accepts_nested_attributes_for :frames, allow_destroy: true
end

class Frame < ApplicationRecord
  belongs_to :parent, polymorphic: true
  has_many :frame_variables
end

class FrameVariable < ApplicationRecord
  belongs_to :frame
  
  attr_accessor :_delete

  before_save :discard_if_cleared

  def discard_if_cleared
    throw :abort if _delete == true
  end
end
def create
  @document = current_user.documents.new(document_params)
  if @document.save
    redirect_to documents_path
  else
    redirect_to new_document_path(template: @document.template), flash: { error: "The document you tried to create was invalid: #{@document.errors.full_messages}" }
  end
end

What am I missing?

CodePudding user response:

You possibly have two options here:

  1. To use a combination of accepts_nested_attributes_for and :reject_if block to not save the association conditionally by checking the _delete in the :reject_if block.

Catch there is in your current setup your accepts_nested_attributes_for is on Document and not on Frame. If that can be changed this might work out.

  1. To not build the Document object in one shot using nested attributes. Instead "open" up your parametes in the create action. The build the Frame and it's relevant children based on _delete for the FrameVariable. and the "attach" the final Frame to the Document as usual using build

Sorry for a vague answer, but not understanding the full context of your models and what you can modify, these are the general approaches I can think of.

Finally doing it in before_save is def a bad idea because when you are building out the full model using accepts_nested_attributes_for rails will use a commit block and revert everything if something in the chain rejects it.

This blog goes in some details about using :reject_if

https://www.pluralsight.com/guides/ruby-on-rails-nested-attributes

Here's another example of using the reject block:

Rails: use REJECT_IF only on CREATE action for nested attributes

  • Related