2017-06-01 82 views
-1

我想覆蓋我的關係中的<< setter。例如,給定:Rails覆蓋關係中的活動記錄集setter

class Library < ActiveRecord::Base 
    has_many :groups 

    def readers 
    groups.find_by(name: 'readers').users 
    end 
end 

class Group < ActiveRecord::Base 
    has_many :group_memberships 
    has_many :users, through: :group_memberships 
end 

class GroupMembership < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :group 
end 

class User < ActiveRecord::Base 
    has_many :groups, through :group_membership 
end 

我要像做

someLibrary.readers << user1 

和一些額外的事情後,這種情況發生。

的代碼應該是這個樣子:

def <<(objects) 
    super objects 
    #do other things here 
end 

它應該在哪裏呢?我想在Group,如:

class Group 
    ... 
    def users<<(objects) 
    super objects 
    #do stuff 
    end 
end 

,但我只是想這樣做,當我在閱讀器調用<<

我想知道是否有知道我是否在一組用戶關係調用<<的方式,或者我是否有權訪問組對象的時候,我就調用用戶組<<方法通過關係。

我想這樣做,因爲它看起來不錯。最簡單的方法是定義單獨的方法來設置讀者(並且更加明確),但是我想知道在activerecord或ruby中是否有可能。

編輯:

是的,我知道,壓倒一切的核心方法是壞事,人們去地獄的是,亞達內容十分重要。

我只是好奇它是如何完成的。就像爲了學習的目的。

除了目的只是重寫<<方法在那個特定的關係,所以很可能有人可能會有一些理由爲什麼有人可能會這樣做。

+0

在你的'AR'版本中'someLibrary.readers.class'是什麼? – mudasobwa

+0

恕我直言,覆蓋Rails方法是一個可怕的想法。你爲什麼不添加一個名稱反映它真正做的新方法?你試圖通過重寫Rails核心方法來實現什麼? – spickermann

回答

1

強制性免責聲明:

不建議您這樣做,在 '重要' 的代碼。改變這種方法的行爲會混淆其他開發人員(以及未來的自我),並導致各種意想不到的行爲改變!

但假設這是「玩票」 ......

基於上述信息,someLibrary.readers返回User記錄的集合。所以我們需要做的是將所需的行爲添加到該類。

通常你可以只定義一個類的方法,通過以下兩種方式之一進行:

class User 
    def self.foo 
    puts 'this works!' 
    end 

    class << self 
    def bar 
     puts 'this works too!' 
    end 
    end 
end 

有了上面的,你可以調用類的方法:

someLibrary.readers.foo 
someLibrary.readers.bar 

...但是,這裏有一些導軌黑色魔法。someLibrary.readers實際上是User::ActiveRecord_Associations_CollectionProxy的一個實例,並且上述方法正在動態拾取並附加到ActiveRecord::Associations::CollectionProxy

由於這種動態方法定義的,它不可能覆蓋現有的Rails方法(如<<)以這種方式。取而代之的是,我們需要猴補丁直接User::ActiveRecord_Associations_CollectionProxy類:

class User 
    class ActiveRecord_Associations_CollectionProxy 
    def <<(objects) 
     super(objects) 
     # do stuff 
    end 
    end 
end 

如果您正在尋找然而,這樣做的更好的方法,我建議使用服務對象設計模式。然後,您可以在一個乾淨而孤立的抽象中封裝與創建/更新/刪除用戶,庫等有關的任何更復雜/定製的邏輯。

0

更成立的方式來做到這一點...

class Library < ActiveRecord::Base 
    has_many :groups 
    has_one :reader_group -> {groups.find_by(name: 'readers')} 
    has_many :readers, through: :reader_group, class_name: 'User', foreign_key: 'user_id' 
end 

就是這樣。你現在可以做

my_library.readers << another_user 
+0

這是一個很好的代碼改進,但它實際上並沒有回答這個問題?... –