2014-01-15 114 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

我剛剛更新了我的答案,並提供了一個解決方案(您最初的想法和我的原始答案的結合),它似乎正在工作...... –