2012-03-28 8 views
16

ich mit einer polymorphen Assoziation wie dies ein Activerecord-Modell habe:Delegierten alle Methodenaufrufe auf einem Modell einer Vereinigung

class Reach < ActiveRecord::Base 
    belongs_to :reachable, :polymorphic => true 
end 

Dieses Modell verhält sich wie ein Proxy. Was ich tun muss, ist, alle Methodenaufrufe für dieses Objekt an das zugehörige Objekt :reachable weiterzuleiten. Ich denke, delegate wird hier nicht helfen, weil ich explizit alle Methoden benennen muss, die ich delegieren muss. Ich brauche etwas wie delegate :all, um alle Methoden zu delegieren (nicht all Methode).

Antwort

16

Es gibt zwei Dinge, die Sie hier tun können:

  1. Je langsamer (Performance-weise), aber einfachere Methode ist method_missing zu verwenden:

    class Reach < ActiveRecord::Base 
    
        def method_missing(method, *args) 
        return reachable.send(method, *args) if reachable.respond_to?(method) 
        super 
        end 
    end 
    
  2. Je schneller leistungs Methode wäre, Definieren Sie jede Methode dynamisch, die Sie delegieren möchten:

    class Reach < ActiveRecord::Base 
    
        [:all, :my, :methods, :here].each do |m| 
        define_method(m) do |*args| 
         reachable.send(m, *args) 
        end 
        end 
    end 
    

Sie können diese Methode sogar auf eine dynamischere Weise verwenden, wenn Sie möchten, indem Sie die Reach-Klasse verwenden, indem Sie die Methoden finden, die für sie definiert sind, und nur diejenigen für Reachable definieren. Ich würde es aber mit der Hand machen, weil es einige gibt, die Sie wahrscheinlich nicht aufnehmen wollen.

+0

in Bezug auf Ihren ersten Ansatz. Wird dies nicht die Methode auf dem 'Reach' Objekt aufrufen, wenn es dort existiert? – badawym

+0

Ja, tut mir leid, ich glaube, ich habe "reach" getippt, wenn ich "erreichbar" meinte. – Veraticus

+6

Wenn Sie eine Liste von Methoden haben, die Sie delegieren möchten, können Sie sie einfach wie gewohnt delegieren. – Andrew

4

Für Rails, habe ich die folgenden:

class User < ApplicationRecord 
    has_one :member 
    delegate (Member.new.attributes.keys - User.new.attributes.keys), to: :member 
end 

die - User.new... ist nicht vorhandene Attribute außer Kraft setzen auf User (zB created_at)

Ich bin nicht sicher, wie dieser Ansatz mit Polymorphismus funktionieren würde , jedoch.

1

Ich habe eine elegante Möglichkeit gefunden, das Problem mit Verfeinerungen zu nähern. Es gibt bereits eine Klasse in der Standardbibliothek, die es ermöglicht, jeden Methodenaufruf an ein Zielobjekt zu delegieren. Delegator and by extension SimpleDelegator Jetzt gibt es eine Möglichkeit SimpleDelegator in Ihre Vererbungskette einfügen, ohne es zu erben direkt Verfeinerungen mit:

def self.include_delegator 
    mod = Module.new do 
    include refine(SimpleDelegator) { yield if block_given? } 
    end 
    self.send :include, mod 
end 
include_delegator 

Um nun wie so nutzen SimpleDelegator setzen die Delegation Ziel in einem nach initialisieren Rückruf zu nehmen:

Dies ist gleichbedeutend mit Erben direkt von SimpleDelegator und Festlegen der Delegation in der Konstruktion, gibt es keine manuelle Verwaltung von Methoden zu delegieren und Sie können vermeiden, die Methode fehlt.

Verwandte Themen