Home > Software design >  How to prevent last child from being destroyed unless parent is destroyed
How to prevent last child from being destroyed unless parent is destroyed

Time:03-07

We have 2 simple models where a workspace has many memberships. We need to prevent the last membership from being destroyed unless it's workspace is destroyed.

This code isn't letting us destroy memberships when we destroy the workspace -- could someone tell me what I'm doing wrong or if there's a better way to do this?

class Workspace < ApplicationRecord
  has_many :memberships, dependent: :destroy
end
class Membership < ApplicationRecord 
  belongs_to :workspace, counter_cache: true
  before_destroy :ensure_one_member, unless: -> { workspace.destroyed? }
  
  private
  def ensure_one_member
    raise "Can't delete the last member" if workspace.memberships.count == 1
  end
end
% rails c
Loading development environment (Rails 7.0.2.2)
irb(main):001:0> Workspace.last.destroy
  Workspace Load (0.6ms)  SELECT "workspaces".* FROM "workspaces" ORDER BY "workspaces"."id" DESC LIMIT $1  [["LIMIT", 1]]
  TRANSACTION (0.2ms)  BEGIN                                  
  Membership Load (0.8ms)  SELECT "memberships".* FROM "memberships" WHERE "memberships"."workspace_id" = $1  [["workspace_id", 3]]
  Membership Count (0.6ms)  SELECT COUNT(*) FROM "memberships" WHERE "memberships"."workspace_id" = $1  [["workspace_id", 3]]
  TRANSACTION (0.2ms)  ROLLBACK                               
/Users/vince/code/myapp/app/models/membership.rb:6:in `ensure_one_member': Can't delete the last member (RuntimeError)

CodePudding user response:

As fas as i know, rollback occurs because rails trying to delete Members before Workspace so ensure_one_member still triggered even when you try to destroy Workspace. It's not a perfect but destroyed_by_association check may solve your problem. Youn can check related discussion here

  • Related