2012-01-23 3 views
6

既存のhas_manyまたはhas_and_belongs_to_manyの関係にafter_addafter_removeコールバックを動的に追加する方法はありますか?例えばhas_manyまたはhabtmのafter_addコールバックとafter_removeコールバックを動的に作成しますか?

、私はモデルUserThing、そして参加モデルUserThingRelationshipを持っている、とUserモデルは、このようなものであると仮定します。私はそのモジュールで、できるようにしたいと思い

class User < ActiveRecord::Base 
    has_many :user_thing_relationships 
    has_many :things, :through => :user_thing_relationships 
end 

Userを拡張すると、:after_add:after_removeのコールバックがUser.has_many(:things, ...)の関係に追加されます。すなわち、

class User < ActiveRecord::Base 
    has_many :user_thing_relationships 
    has_many :things, :through => :user_thing_relationships 

    does_awesome_stuff :things, :my_callback 
    def my_callback; puts "awesome"; end 
end 

が効果的

class User < ActiveRecord::Base 
    has_many :user_thing_relationships 
    has_many :things, :through => :user_thing_relationships, :after_add => :my_callback, :after_remove => :my_callback 

    def my_callback; puts "awesome"; end 
end 

これは、など、after_saveを追加するためにかなり効果的だモデルへのコールバックを行うことができると同じになるように

module DoesAwesomeStuff 
    def does_awesome_stuff relationship, callback 
    # or however this can be achieved... 
    after_add(relationship) callback 
    after_remove(relationship) callback 
    end 
end 

のようなものを持っているにActiveRecord::Base#after_saveは単なるクラスメソッドなので、拡張されています。

答えて

5

私はActiveRecord::Reflectionを使用して、次のを思い付くことができました:

module AfterAdd 
    def after_add rel, callback 
    a = reflect_on_association(rel) 
    send(a.macro, rel, a.options.merge(:after_add => callback)) 
    end 
end 

class User < ActiveRecord::Base 
    extend AfterAdd 

    has_many :user_thing_relationships 
    has_many :things, :through => :user_thing_relationships 

    after_add :things, :my_callback 

    def my_callback 
    puts "Hello" 
    end 
end 

私は自分の質問に答えることをしたくないので、私は他の誰かが出てくることができれば自分が信用に答える与えることはありません数日後にはより良いソリューションを提供します。

+0

が、私の知る限りでは、あなたのコールバックはありません、漏れ出しますでしょうか?私。 2つのスレッドが同時にafter_addを実行する場合、どのコールバックが有効であるか分からないでしょうか? – nambrot

10

最も簡単には、これを埋め込むため申し訳ありません

User.after_add_for_things << lambda do |user, thing| 
    Rails.logger.info "#{thing} added to #{user}" 
end 
+0

どうやってこの動的機能について知ることができたのか不思議です – davidtingsu

+0

Railsソースを読むことで! – glebm

+0

この機能は 'lib/active_record/associations/builder/collection_association.rb'の' define_callback'にあります。 (https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/builder/collection_association.rb) –

関連する問題