modelの削除可否チェックを実装したい
親modelが複数の子modelを持っているケースで、
parent.rb
class Parent < ActiveRecord::Base
has_many :children, dependent: :destroy
end
child.rb
class Child < ActiveRecord::Base
belongs_to :parent
end
ここで、子modelが0件になってしまう場合は削除できないのような削除可否チェックを挟みたい場合は、 子modelにbefore_destory で実装すると良い。
child.rb
class Child < ActiveRecord::Base
belongs_to :parent
# 追加
before_destroy :must_not_destroy_last_one_child
private
def must_not_destroy_last_one_child
throw(:abort) if (parent.children - [self]).empty?
end
end
親modelごと削除したいときに子modelのbefore_destoryが邪魔になる
このままだと、親modelごと削除するときに子modelのbefore_destoryに引っかかってエラーとなってしまう。
親modelごと削除の場合は、destroyed_by_association が設定されているので、その値を見てreturnしてしまえばよい。
child.rb
class Child < ActiveRecord::Base
belongs_to :parent
before_destroy :must_not_destroy_last_one_child
private
def must_not_destroy_last_one_child
return if destroyed_by_association.present? # 追加
throw(:abort) if (parent.children - [self]).empty?
end
end
これで解決
余談
親model側で、 dependent: :delete_all
に変えることでActive Record コールバックを発生させないというアプローチもあるが、これはおすすめしない。
今後、子modelにコールバックが追加されたり、孫modelが増える可能性とか色々を考慮すると、不正なデータを発生させないために考えることが増えてしまうので。。