2010-12-16 4 views
6

has_many:throughアソシエーションとafter/before-destroyコールバックがトリガーされていない問題が発生しました。HMT collection_singular_ids =結合モデルの削除は直接です。破棄コールバックはトリガーされません。

私はユーザー、グループ、およびメンバシップと呼ばれる中間的な関係を持っています。 関連するチェックボックスをオフにしたときに新しいメンバーシップレコードを作成して、ユーザーをグループに登録できるようにするフォームがあります。基本的にgroup_idの配列。

はこのようなものになります。

Which group would you like to join? (check all that apply) 
[] Group A 
[] Group B 
[] Group C 

をそして私は、このようなアクティビティログテーブルにグループに参加したり、グループを離れるなどのアクションを記録し、他のいくつかの重要度の低いthignsを行いたいです。

私は次のように定義されています

class Group < AR::Base 
    has_many :memberships 
    has_many :users, :through => :memberships 
end 

class Membership < AR::Base 
    belongs_to :user 
    belongs_to :group 

    after_create :log_event_to_audit_table 
    after_destroy :log_event_to_audit_table 

end 

class User < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, :through => :memberships 

    attr_accessible :group_ids # enables mass-assignment 
end 

新会員記録が期待通りafter_createが実行されて作成されたとき。しかし、after_destroyはトリガされません!

Googleが-INGのと私は理由を発見ドキュメントまで読んだ後:

「モデルへの参加の自動削除が直接 であるが、無破壊するコールバックが がトリガされている」 - Rubyのガイドから。

Hmmmmmm

...

だから、参加モデルの(この場合はメンバーシップの)コールバックがトリガされていない破壊します。まあ、それはダウン者です。理由は何ですか?

この問題を回避する最も良い方法は何ですか? membership.destroyを直接呼び出すUserモデルで自分のmembership_ids =メソッドを定義する必要がありますか?

このようなシナリオでは、ベストプラクティスに関する提案があります。

ありがとうございます!慎重APIのドキュメントを調べた後

答えて

9

、has_manyのとHABTMはちょうどこのような場合のために、いくつかのオプションを持って判明:

before_add、after_add、before_removeと

私が得たどのように多くの回答から判断
class User < ActiveRecord::Base 
    has_many :groups, :through => :memberships, :after_remove => :your_custom_method 
end 

after_remove、これは非常によく文書化された/使用された機能であってはなりません。

自分自身と私のようにつまずくかもしれない他の人のためにここに注目してください。

私は最近、同じ問題で苦労して関連性を拡張し、そのdeleteメソッドをオーバーライドすることで、それを解決してきました
+0

これは非常識です...多くのあなたに感謝します。私はこれとあまりにも長い時間をかけて苦労していました。 –

+0

これはRailsのやり方です。それでも、 'group'を削除した後に引き起こされるアクションは、' user'から 'group'を削除することが実際に' membership'を削除するため、 'membership'モデルの一部であるべきだと思います。あまりにも悪いことに、Railsはこれを避けることはできません。 –

-1

:サイドノートとして

class User < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, :through => :memberships do 
    def delete(*args) 
     groups = args.flatten 
     # destroy memberships in order to trigger their callbacks: 
     proxy_association.owner.memberships.where(group_id: groups).destroy_all 
     super 
    end 
    end 
    ... 
end 

、私たちは確実に依存することはできませんように見えますRailsのモデルコールバック。これは一種の失望です。

関連する問題