动态创建has_many或habtm的after_add和after_remove回调?

时间:2012-01-23 21:28:10

标签: ruby-on-rails activerecord callback has-many-through

有没有办法动态地将after_addafter_remove个回调添加到现有的has_manyhas_and_belongs_to_many关系中?

例如,假设我有模型UserThing和加入模型UserThingRelationshipUser模型是这样的:

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, ...)关系中。即,有类似

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

那样

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等回调到正在扩展的模型,因为ActiveRecord::Base#after_save只是一个类方法。

2 个答案:

答案 0 :(得分:11)

最简单的是

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

答案 1 :(得分:7)

我可以使用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

我不想回答我自己的问题,所以如果其他人能在接下来的几天内找到更好的解决方案,我也不会给自己回答。