2016-05-10 15 views
0

Ist es möglich, den Operator << für ein Postgres-Array-Typ-Attribut, das von ActiveRecord erstellt wurde, zu überschreiben?überschreiben Postgres-Array-Typ Shift-Operator

Spaltendefinition:

t.time "hours", default: [], array: true 

Dies scheint zu funktionieren:

def hours=(arr) 
    super(arr.map {|h| # do some stuff with each element}) 
end 

Dies gilt nicht:

def hours<<(val) 
    super(# do some stuff before pushing) 
end 

Beachten Sie, dass dies nicht eine Vereinigung von has_many erstellt ist, wo ich kann Überlademethoden einen Block hinzufügen.

Antwort

1

Diese Methode ist in der Array-Klasse definiert, Sie können dies also nicht in Ihrem Modell tun.

Eine Möglichkeit, das erreichen kann, ist durch eine mixin

module WithShift 
    def << arg 
    # do something 
    end 
end 


def hours 
    read_attribute("hours").extend(WithShift) 
end 

Dies ist langsamer. Aber es sollte kein Show-Stopper sein. Hier ist ein grundlegender Maßstab.

require 'benchmark/ips' 
module WithShift 
    def << arg 
    end 
end 
def with_extend; [1,2,3].extend(WithShift); end 

def base; [1,2,3]; end 

Benchmark.ips do |x| 
    x.report("base") { base } 
    x.report("with extend") { with_extend } 
    x.compare! 
end 


Calculating ------------------------------------- 
       base  5.506M (± 9.1%) i/s -  27.415M in 5.022561s 
     with extend 349.984k (± 7.6%) i/s -  1.769M in 5.081799s 

Comparison: 
       base: 5505897.2 i/s 
     with extend: 349984.1 i/s - 15.73x slower 
+0

Gibt es eine Leistung/Speicherkosten für die Einbeziehung des Moduls jedes Mal, wenn das Stundenattribut verwendet wird? – iftheshoefritz

+0

Ja, es ist ungefähr 15x langsamer. Aber vernachlässigbar, es sei denn, Sie nennen diese Methode viele Male. Beachten Sie auch, dass 'include' nicht funktioniert hat. Was Sie eigentlich tun möchten, ist 'extend' zu verwenden. Ich habe meine Antwort bearbeitet und einen Benchmark hinzugefügt –

1

Aufbauend auf @ ismael Antwort, in rubin = Teil der Setter-Methode Name ist.

Dieser Code def hours= arr end schafft eine Methode namens hours= während << ein Operator ist, und wird nicht als Teil eines Methodennamen erlaubt. Es ist ist möglich, benutzerdefinierte Operatoren zu definieren, und @ismael enthält ein Beispiel dafür.