2010-05-23 101 views
31

有沒有辦法重寫ActiveRecord關聯提供的方法之一?Rails:重寫ActiveRecord關聯方法

例如說我有以下典型的多態的has_many:通過關聯:

class Story < ActiveRecord::Base 
    has_many :taggings, :as => :taggable 
    has_many :tags, :through => :taggings, :order => :name 
end 


class Tag < ActiveRecord::Base 
    has_many :taggings, :dependent => :destroy 
    has_many :stories, :through => :taggings, :source => :taggable, :source_type => "Story" 
end 

正如你可能知道,這增加的相關方法,以類似標籤的故事模型整體轉換,標籤< <,標籤= ,tags.empty?等。

我該如何去重寫這些方法之一?具體是標籤< <方法。重寫一個普通的類方法是很容易的,但我似乎無法找到關於如何重載關聯方法的任何信息。做類似

def tags<< *new_tags 
    #do stuff 
end 

當它被調用時會產生語法錯誤,所以它顯然不那麼簡單。

+2

你在做什麼?這可能最終會打破其他ActiveRecord功能,並且可能有更好的方法來做你正在嘗試的東西 – Gareth 2010-05-23 07:19:54

回答

53

您可以使用塊與has_many與方法擴展您的關聯時間。請參閱評論「使用塊來擴展您的關聯」here
覆蓋現有的方法也有效,但不知道它是否是一個好主意。

has_many :tags, :through => :taggings, :order => :name do 
    def << (value) 
     "overriden" #your code here 
     super value 
    end  
    end 
+0

當然!忘了那個。這可能是完成你之後的最佳方式。 – 2010-05-24 06:52:03

+1

你會怎麼稱呼最初的方法? (我想重寫構建方法,添加一些默認值,然後調用原始文件) – 2012-03-06 18:06:06

+1

@EranKampf不''超'做的伎倆? – lulalala 2012-11-14 08:57:03

0

我認爲你想爲簽名,這應該工作,或者以下是相當的,如果你需要重寫多個方法有點清潔def tags.<<(*new_tags)

class << tags 
    def <<(*new_tags) 
    # rawr! 
    end 
end 
+0

我不認爲這兩種方法都有效。看起來你正在試圖擴展由'tags'方法返回的值的特徵類。 – 2010-05-23 07:38:51

+0

它定義了一個由'tags'返回的特徵類中的方法,它可能是一個數組。這有一個新的實例方法添加到數組中的效果,這是我瞭解原始問題的要求。 'extend'在ruby中具有特定的含義,這不是這裏發生的事情。 – x1a4 2010-05-23 07:50:18

+0

你是對的,那正是它在做的。我想我只是不明白你建議把這些代碼放在哪裏。無論如何,我想我回答了幾乎相同的事情,只是有更多的上下文。 – 2010-05-23 08:07:03

0

您將不得不定義標籤方法以返回具有<<方法的對象。

你可以這樣做,但我真的不會推薦它。只需向模型中添加一個方法,而不是試圖替換ActiveRecord使用的某個方法即可。

這本質上運行默認tags方法添加一個< <方法到結果對象並返回該對象。這可能是有點資源密集型的,因爲它創建了一個新的方法,每次運行它

def tags_with_append 
    collection = tags_without_append 
    def collection.<< (*arguments) 
    ... 
    end 
    collection 
end 
# defines the method 'tags' by aliasing 'tags_with_append' 
alias_method_chain :tags, :append 
0

我使用的方法是擴展關聯。你可以看到我處理的方式「量」屬性在這裏:https://gist.github.com/1399762

它基本上可以讓你只是做

has_many : tags, :through => : taggings, extend => QuantityAssociation 

不知道您希望通過重寫方法其很難知道,如果你要實現什麼可以做同樣的事情。

0

這可能對您的情況沒有幫助,但可能對其他人進行調查有用。

協會回調: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

從文檔實例:

class Project 
    has_and_belongs_to_many :developers, :after_add => :evaluate_velocity 

    def evaluate_velocity(developer) 
    ... 
    end 
end 

另見協會擴展:

class Account < ActiveRecord::Base 
    has_many :people do 
    def find_or_create_by_name(name) 
     first_name, last_name = name.split(" ", 2) 
     find_or_create_by_first_name_and_last_name(first_name, last_name) 
    end 
    end 
end 

person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson") 
person.first_name # => "David" 
person.last_name # => "Heinemeier Hansson" 
17

如果您要訪問的Rails 3.2的模型本身,你應該使用proxy_association.owner

實施例:

class Author < ActiveRecord::Base 
    has_many :books do 
    def << (book) 
     proxy_association.owner.add_book(book) 
    end 
    end 

    def add_book (book) 
    # do your thing here. 
    end 
end 

查看關於直接重寫添加的方法documentation

+0

這仍然是在Rails 5.1的情況 – coconup 2017-09-28 08:11:28

+0

@coconup這不適用於我在rails 5.1中 - 重寫的<<方法根本不會被調用:-( – dowi 2018-02-22 09:12:03

0

Rails guides文檔。

OP的問題與重寫<<可能是唯一的例外,爲此,跟着the top answer。但它不適用於has_one=賦值方法或getter方法。