2014-01-15 115 views
2

我有若干类,如下面的:从混入添加协会而不覆盖现有关联

class Event < ActiveRecord::Base 
    include PreventUpdate 

    has_many :participants, conditions: ... 
    has_many :venues, conditions: ... 
    has_many :companies, conditions: ... 
end 

我有一个处理prevent_update逻辑(obj是在过去,OBJ被禁止)的类的模块,并作为它的一部分,它查询包含类的has_many关联,以便为这些关联编写before_add钩子。

module PreventUpdate 
    extend ::ActiveSupport::Concern 

    included do 
    self.reflect_on_all_associations(:has_many).each do |assoc| 
     has_many assoc.name, before_add: :prevent_update 
    end 
    end 

    def prevent_update 
    #core prevent update logic 
    end 

end 

唯一的问题是动态添加的和原始的has_many语句相互覆盖。其中重写哪个取决于包含该模块的包含类中的哪个位置。

有什么办法可以动态添加和原始声明可以“积累”,即模块的声明可以简单地添加到原始文件而不会覆盖?

回答

2

这是未经测试,但你应该能够只是做:

included do 
    self.reflect_on_all_associations(:has_many).each do |assoc| 
    assoc.options.merge!(:before_add => :prevent_update) 
    end 
end 

这将需要关注includehas_many声明之后到来。如果你想在他们面前做include,您可以添加:

module ClassMethods 
    def modify_associations 
    self.reflect_on_all_associations(:has_many).each do |assoc| 
     assoc.options.merge!(:before_add => :prevent_update) 
    end 
    end 
end 

然后:

# ...  
has_many :companies, conditions: ... 
modify_associations 

编辑

这应该工作:

included do 
    self.reflect_on_all_associations(:has_many).each do |assoc| 
    has_many assoc.name, assoc.options.merge(:before_add => :prevent_update) 
    end 
end 
+0

我见这确实更新了assoc.options,重新加载页面,但它仍然没有当添加实际发生时(我将模块包括在原始关联行下面),请选择before_add回调。 – rfish26535

+0

什么工作,但生产太丑了...我可以添加在你的assoc.options.merge!方法(抱歉,我不知道如何格式化)assoc_string =“has_many:#{assoc.name}”; assoc.options.each do | k,v |; value = v.is_a?(Symbol)? “:#{v}”:“'#{v}'”; assoc_string <<“,#{k}:#{value}”; 结束; eval(assoc_string) – rfish26535

+0

我刚刚更新了我的答案,并提供了一个解决方案(您最初的想法和我的原始答案的结合),它似乎正在工作...... –