2010-05-23 19 views
31

Czy istnieje sposób na zastąpienie jednej z metod udostępnianych przez skojarzenie ActiveRecord?Szyny: Nadpisywanie metody asocjacji ActiveRecord

powiedzieć na przykład mam następujący typowy polimorficzny has_many: poprzez stowarzyszenia:

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 

Jak zapewne wiesz to dodaje całe mnóstwo związanych z nimi metod do modelu Story jak tagi, tagi < <, tags = , tags.empty ?, itp.

Jak mogę pominąć jedną z tych metod? W szczególności metoda tagów: < <. Łatwo jest przesłonić normalne metody klasy, ale nie mogę znaleźć żadnych informacji o tym, jak nadpisać metody asocjacji. Powoduje wystąpienie błędu składni po wywołaniu, co powoduje, że nie jest to takie proste.

+2

Co próbujesz zrobić? To może skończyć się zerwaniem z innymi funkcjami ActiveRecord i prawdopodobnie istnieje lepszy sposób na zrobienie tego, co próbujesz. – Gareth

Odpowiedz

53

można użyć bloku z has_many przedłużyć swój związek z metod. Zobacz komentarz "Użyj bloku, aby rozszerzyć swoje skojarzenia" here.
Zastępowanie istniejących metod również działa, nie wiem jednak, czy jest to dobry pomysł.

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

Oczywiście! Zapomniałem o tym. Jest to prawdopodobnie najlepszy sposób robienia tego, o co prosisz. –

+1

A jak nazwałbyś oryginalną metodę? (Chcę zastąpić metodę kompilacji, dodać pewne wartości domyślne, a następnie wywołać oryginalną) –

+1

@EranKampf nie robi "super"? – lulalala

0

Wydaje mi się, że chcesz podpis def tags.<<(*new_tags) dla podpisu, który powinien działać, lub następujące, które jest równoważne i nieco bardziej przejrzyste, jeśli chcesz zastąpić wiele metod.

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

Nie sądzę, aby któryś z nich działał. Wygląda na to, że sugerujesz, że próbujesz rozszerzyć Eigenclass o wartość zwróconą przez metodę 'tags'. –

+0

Definiuje ona metodę w ramach eigenclass tego, co jest zwracane przez 'tags', która jest prawdopodobnie tablicą. Doprowadziło to do dodania do tablicy nowej metody instancji, w której zrozumiałem pierwotne pytanie, które należy zadać. 'extend' ma określone znaczenie w ruby ​​i nie jest to tutaj, co się dzieje. – x1a4

+0

Masz rację, właśnie to robi. Sądzę, że po prostu nie rozumiem, gdzie sugerujesz, aby umieścić ten kod. W każdym razie myślę, że odpowiedziałem prawie tak samo, tylko z odrobiną kontekstu. –

0

Będziesz musiał zdefiniować metodę tagów, aby zwrócić obiekt, który ma metodę <<.

Można to zrobić tak, ale naprawdę nie polecam. Lepiej byłoby po prostu dodać metodę do swojego modelu, która robi to, co chcesz, niż próbować zastąpić coś, czego używa ActiveRecord.

To zasadniczo uruchamia domyślną metodę tags, która dodaje do obiektu wynikowego metodę < < i zwraca ten obiekt. To może być nieco dużych nakładów, ponieważ tworzy nową metodę za każdym razem, gdy go uruchomić

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

Metoda, której używam, służy do rozszerzenia powiązania. można zobaczyć sposób obsłużyć „ilość” atrybuty tutaj: https://gist.github.com/1399762

To w zasadzie pozwala po prostu zrobić

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

Nie wiedząc dokładnie, co chcąc osiągnąć poprzez nadpisanie metody jej trudno wiedzieć, czy mógł zrobić to samo.

0

Może to nie być pomocne w twoim przypadku, ale może być przydatne dla osób, które się tym zajmują.

Stowarzyszenie oddzwaniania: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

przykład z docs:

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

    def evaluate_velocity(developer) 
    ... 
    end 
end 

Zobacz także Stowarzyszenie rozszerzeniach:

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

Jeśli chcesz uzyskać dostęp model sam w Rails 3.2 zalecana użyj proxy_association.owner

przykład:

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 

Patrz documentation

+0

to nadal jest w przypadku Rails 5.1 – coconup

+0

@coconup to nie działa dla mnie w szynach 5.1 - nadpisująca metoda << nie jest w ogóle wywoływana :-( – dowi

0

Rails guides dokumenty o nadrzędne dodane bezpośrednio metody.

Problem PO z przesłonięciem << prawdopodobnie jest jedynym wyjątkiem od tego, dla którego następuje the top answer. Ale nie zadziałałoby to w przypadku metod przypisywania ani metod gettera.

Powiązane problemy