テーブル関連、has_oneとかhas_manyとかの関連を持っているとき、
ついついActiveRecord::Base.destroyとかをオーバーライドしたくなるときがある。
例:
class Parent < AciveRecord::Base
has_many :chidren, :dependent=>:destroy
# 属性:deleted, :boolean, :default=>false
end
class Child < AciveRecord::Base
belongs_to :parent
# 属性:deleted, :boolean, :default=>false
end
親も子も関連する全員が@deletedがtrueになったときだけ全削除の実行に入る、
という必要があったとする。
親の方は簡単で、エイリアスを作ってオーバーライドすればいい。
class Parent < AciveRecord::Base
has_many :children, :dependent=>:destroy
alias :destroy! :destroy
def check_destory
if # 自分と子が全員削除可能
return self.destory!
end
end
def destroy
self.deleted = true
return self.save
retrun check_destroy
end
end
てな感じ。
問題は子のほう。
メソッドを普通にオーバーライドすると、親の方が削除された時に、
自動的にdestoryが呼ばれるので無限ループに陥ってしまう。
で、苦肉の策で考えたのがこの方法。
class Child < ActiveRecord::Base
belongs_to :parent
def destroy
if caller.to_s =~ /.+has_many_dependent_destroy_for_message_receiver_relations.+/
return super
else
self.deleted = true
self.save
return self.parent.check_destroy
end
end
end
callerで呼び出し元をたどって、
そこにhas_many_dependent_destroy_for_message_receiver_relations
(関連で:dependent=>:destroyを設定したときに、自動で呼び出される)
が含まれていたら親が削除された一連の動作で削除されていると判断して、
superを呼び出し、
それ以外はフラグを設定してそこで処理を握りつぶすという方法。
これなら、親が削除されたとき以外は削除されずにすむ。
callerのチェックとかってあんまりやりたくないんだけど、
この方法ってなんか問題あるのかしら。
滅多に使わない方法なのでちょっと悩む。
てか、なんかほかのもっといい方法があったら教えてほしい。
PR