2010-12-09 12 views
0

Ich habe einen wiederholten Codeblock, der einige Variablen in einer Reihe von verschiedenen Controller-Methoden initialisiert. Gibt es eine Möglichkeit für mich, dieses DRY mit einer Modellmethode zu machen, anstatt den gleichen Codeblock in jeder Controller-Methode zu wiederholen?Ruby on Rails: DRY einen wiederholten Codeblock, der einige Variablen initialisiert

Grundsätzlich ist es für eine soziale Website, und es zieht die Freundesliste eines Benutzers hoch und erstellt dann Buckets mit Freunden basierend auf den Berechtigungen des Benutzers, die in einem Freundschaftsmodell gespeichert sind. Diese wiederholte Initialisierung von Buckets ist, was ich versuche, DRY zu machen. Normalerweise würde ich eine Modellmethode verwenden, aber in diesem Fall werden 3 separate Variablen basierend auf einer Datenbankabfrage initialisiert, und dies wird oft genug genannt, ich möchte es nicht unnötig ineffizient machen, indem ich die Datenbank 3 anstoße mal. In C würde ich nur Zeiger verwenden, die als Variablen übergeben werden.

Es geht ungefähr so:

def example_method 
    friendships = @user.friendships 
    view_permission_friends = [] 
    write_permission_friends = [] 
    message_permission_friends = [] 
    for friendship in friendships 
    if friendship.view_permission then view_permission_friends << friendship.friend_id end 
    if friendship.write_permission then write_permission_friends << friendship.friend_id end 
    if friendship.message_permission then message_permission_friends << friendship.friend_id end 
    end 
    #Do something with the 3 initialized arrays here 
end 

Antwort

1

Ich dachte darüber nach ein wenig, und ich denke, dieser Code in Ihre Benutzer-Modell gehen sollte. (Oder wie auch immer Klasse @Benutzer in obigem Beispiel ist.) Zwei Gründe:

  • Es ist sehr spezifisch für den Benutzer, seine Beziehungen und vor allem, wie sie in der Datenbank gespeichert und aus der Datenbank abgerufen werden.
  • Sie müssen den Code nur einmal schreiben: im Benutzermodell.
  • Der schnelle und einfache Weg, der auf dem internen Abfragecaching von Rails beruht, würde so aussehen. Hinzugefügt in den User-Modell:

    def view_permission_friends 
        return friendships.select{|f| f.view_permission} 
    end 
    
    (etc.) 
    

    Ihre Controller dann dies einfach tun: (. Hinweis - es gibt mehr Raum für Optimierung und bessere Flexibilität hier über faul Caching und Parametrisierung der Erlaubnis)

    @viewers = @user.view_permission_friends 
    (etc.) 
    

    0

    Wie wäre es ...

    rv = {} 
    %w(view write message).each do |type| 
        rv["#{type}_permission_friends"] = @user.friendships.select{|f|f.send(:"#{type}_permission")}.collect(&:friend_id) 
    end 
    

    Dies Sie mit Tasten statt einzelner Arrays einen Hash gibt, sollte aber ausreichen.

    +0

    Ich denke, dass ich in meiner Frage, die ich überarbeitet habe, unklar gewesen sein könnte. Ich versuche, die wiederholte Verwendung dieses gesamten Blocks in jeder Controller-Methode auszutrocknen, anstatt den Block selbst zu optimieren. Es ist okay, das Array-Gebäude in separate Zeilen aufzuteilen. Obwohl Sie Recht haben, wenn ich einen Hash von einer Modellmethode zurückgeben würde, würde ich nur die Arrays in den Hash stecken. Ist das der beste Weg, dies zu tun? –

    0

    Verwenden Enumerable#inject, Enumerable#find_all und Object#instance_variable_set:

    def example_method 
        %w{view write message}.inject({}) do |memo, s| 
        friendships = @user.friendships.find_all{ |f| f.send("#{s}_permission") } 
        memo["#{s}_permission_friends"] = friendships 
        end.each do |key, value| 
        instance_variable_set "@#{key}", value 
        end 
    
        # now you have 3 arrays: 
        # @view_permission_friends, @write_permission_friends and @message_permission_friends 
    end