2016-04-26 4 views
1

Ich versuche Affe Patch ActiveRecord :: FinderMethods, um Hash-IDs für meine Modelle zu verwenden. So wird beispielsweise User.find (1) User.find ("FEW"). Leider wird meine überschriebene Methode nicht aufgerufen. Irgendwelche Ideen wie man die find_one Methode überschreibt?Monkeypatch ActiveRecord :: FinderMethods

module ActiveRecord 
    module FinderMethods 
    alias_method :orig_find_one, :find_one 
    def find_one(id) 
     if id.is_a?(String) 
     orig_find_one decrypt_id(id) 
     else 
     orig_find_one(id) 
     end 
    end 
    end 
end 
+3

Dies ist wahrscheinlich eine wirklich schlechte Idee, es könnte die Dinge intern zu brechen. Warum schreiben Sie nicht Ihre eigene alternative Methode und verwenden Sie diese in Ihren Controllern? 'find_hashed_id' stattdessen. – tadman

+0

Danke für Ihre Eingabe, ich gehe mit find_hashed_id :) – krnflake

Antwort

1

Hier ist ein Artikel, der tatsächlich beschreibt, wie zu tun, was Sie durch Überschreiben der User.primary_key Methode wie wollen:

class User 
    self.primary_key = 'hashed_id' 
end 

Welche Sie User.find zu nennen und die „hashed_id“ passieren würde es erlauben:

http://ruby-journal.com/how-to-override-default-primary-key-id-in-rails/

So ist es möglich.

Das sagte, würde ich empfehlen, dagegen zu tun, und stattdessen etwas wie User.find_by_hashed_id verwenden. Der einzige Unterschied ist, dass diese Methode nil zurückgibt, wenn ein Ergebnis nicht gefunden wird, anstatt eine ActiveRecord::RecordNotFound Ausnahme auszulösen. Sie können dies manuell in Ihrem Controller werfen:

def show 
    @user = User.find_by_hashed_id(hashed_id) 
    raise ActiveRecord::RecordNotFound.new if @user.nil? 
    ... continue processing ... 
end 

schließlich eine andere Notiz dies zu erleichtern, auf Sie - Rails hat auch eine Methode, die Sie in Ihrem Modell außer Kraft setzen können, to_param, ihm zu sagen, welche Eigenschaft zu verwenden beim Generieren von Routen. Standardmäßig verwendet es die ID, aber Sie möchten wahrscheinlich die hashed_id verwenden.

class User 
    def to_param 
    self.hashed_id 
    end 
end 

nun in Ihrem Controller wird params[:id] die hashed_id enthalten anstelle der ID.

def show 
    @user = User.find_by_hashed_id(params[:id]) 
    raise ActiveRecord::RecordNotFound.new if @user.nil? 
    ... continue processing ... 
end 
+0

Ich habe manchmal das Gegenteil von 'to_param' genannt, um eine Klasse-Level-Methode' 'from_param' 'für Situationen wie diese zu sein, wenn diese Art von ID-Versteck ist allgegenwärtig. Dies ist eine nette, gründliche Antwort, aber es ist erwähnenswert, dass "if @ user.nil?" Über-kill ist. Zuallererst wird '@ user' niemals' false' sein, also 'wenn '@ user' nicht ausreichen würde, aber wenn Sie' find_by_hashed_id! 'Verwenden, wird dieser Fehler automatisch für Sie ausgelöst. – tadman

+0

Ich war mir nicht bewusst, dass diese zusätzlichen Finder-Methoden "!" Unterstützten, das ist großartig zu wissen, danke. Und ja, 'nil?' Ist eine Angewohnheit, die ich noch nicht geweckt habe! – GoGoCarl

+1

Wie 'save', das einen Fehler und' save! 'Zurückgibt, der eine Ausnahme wirft, gibt es normalerweise eine Ausnahme, die Version jeder gegebenen ActiveRecord Methode wirft. Eines der Dinge, die Ruby am Anfang etwas nerven, ist, dass nur "nil" und "false" logisch falsche Werte sind, "0" und "" sind immer noch wahr. Es ist nur so, dass du deinen Code viel einfacher gestalten kannst, sobald du ihn angenommen hast. Andere Sprachen erfordern viel Arbeit, um zwischen "0" und "falsch" zu unterscheiden. In Rails haben Sie ".präsentieren?", Wenn Sie sich interessieren, wie viel Substanz Ihr Objekt hat. – tadman

1

Ich stimme zu, dass Sie dabei vorsichtig sein sollten, aber es ist möglich.

Wenn Sie eine Methode decode_id haben, die eine Hash-ID zurück in die ursprüngliche ID konvertiert, dann funktioniert das folgende:

In User.rb

# Extend AR find method to allow finding records by an encoded string id: 
def self.find(*ids) 
    return super if ids.length > 1 

    # Note the short-circuiting || to fall-back to default behavior 
    find_by(id: decode_id(ids[0])) || super 
end 

nur sicherstellen, dass decode_id Renditen nil, wenn ein ungültiger Hash übergeben wurde. Auf diese Weise können durch Hash-ID und Standard-ID finden können, so dass, wenn Sie einen Benutzer mit der ID 12345 hatte, dann ist die folgende:

User.find(12345) 
User.find("12345") 
User.find(encode_id(12345)) 

Sollten alle geben den gleichen Benutzer.