2009-05-14 6 views
6

Ich habe Methoden in allen meinen Modellen, die wie folgt aussehen:globalen Methoden in Ruby on Rails-Modelle

def formatted_start_date 
    start_date ? start_date.to_s(:date) : nil 
end 

Ich möchte etwas haben, das automatisch eine Methode, wie dies für jedes Datetime-Feld in jedem Modell schreibt Was ist der beste Weg dies zu tun?

-C

Antwort

16

Ich musste nur antworten, denn es ist ein Spaß Ruby Übung.

Das Hinzufügen von Methoden zu einer Klasse kann auf viele Arten erfolgen, aber eine der besten Möglichkeiten besteht darin, einige der Reflektions- und Bewertungsfunktionen von Ruby zu verwenden.

Erstellen Sie diese Datei in Ihrem Ordner lib als lib/date_methods.rb

module DateMethods 

    def self.included(klass) 

    # get all dates 
    # Loop through the class's column names 
    # then determine if each column is of the :date type. 
    fields = klass.column_names.select do |k| 
        klass.columns_hash[k].type == :date 
       end 


    # for each of the fields we'll use class_eval to 
    # define the methods. 
    fields.each do |field| 
     klass.class_eval <<-EOF 
     def formatted_#{field} 
      #{field} ? #{field}.to_s(:date) : nil 
     end 

     EOF 
    end 
    end 
end 

Jetzt sind es nur in alle Modelle, die es brauchen

class CourseSection < ActiveRecord::Base 
    include DateMethods 
end 

Wenn enthalten, das Modul auf jeder aussehen Datumsspalten und generiere die formated_ Methoden für dich.

Erfahren Sie, wie dieses Ruby Zeug funktioniert. Es macht viel Spass.

Das heißt, Sie müssen sich fragen, ob dies notwendig ist. Ich glaube nicht, dass es persönlich ist, aber es hat Spaß gemacht zu schreiben.

-b-

+2

Warum sammeln und komprimieren auf dem Array lieber als wählen? –

+1

Sie haben Recht. .select wäre hier angemessener. Ich habe Zeiten gefunden, in denen .collect.compact schneller ist, auch wenn es scheint, dass es nicht sein sollte, aber in diesem Fall ist .select eine viel bessere Wahl. Danke, dass du das verstanden hast. Ich konzentrierte mich auf die harten Sachen und verpasste die einfachen Sachen. –

+0

+1 Interessante und lustige Sachen. Wäre besser, wenn Sie die Antwort (hier auf SO) korrigieren würden, um Chris 'Kommentare aufzunehmen. –

11

Es sieht eher aus wie etwas für einen Helfer zu mir. Versuchen Sie dies in der Anwendung Hilfe:

def formatted_date(date) 
    date ? date.to_s(:date) : nil 
end 

Formatierung ist nicht etwas, das wirklich in dem Modell gehört (für genau der Grund, warum Sie entdeckt haben, ... in jedem Modell dieser gemeinsamen Code setzen ist ärgerlich)

Wenn Sie wirklich tun wollen, was Sie sagen, dann können Sie die ActiveRecord Superklasse anpassen und die gewünschte Funktion hinzufügen. Es wäre dann für alle Ihre Modelle verfügbar. Achten Sie darauf, dass Monkeypatching zu unvorhersehbarem und undefiniertem Verhalten und Verwendung auf eigene Gefahr führen kann! Es ist auch ziemlich hacky :)

class ActiveRecord::Base 
    def formatted_start_date 
     start_date ? start_date.to_s(:date) : nil 
    end 
end 

einfach, dass irgendwo haften bleiben, die vor allem anderen in Ihrer Anwendung ausgeführt werden wird, und es wird die Methode der Basisklasse Ihrer Modelle, so dass es für den Einsatz dynamisch hinzufügen .

Oder Sie könnten eine Mischung für alle Ihre Modelle erstellen, aber das scheint ein bisschen übertrieben für eine einzige Methode.

+1

+1 von mir. Ich habe nur die gleiche Antwort geschrieben ... – tomafro

+0

Okay, nehmen wir an, dass es angebracht war, die Formatierung in das Modell zu schreiben, oder dass ich neben der Formatierung mit jedem Datumsfeld in meiner Anwendung noch etwas anderes machen möchte, wie würde ich das tun? –

+0

Ja, aber der 'start_date'-Teil ist hier fest programmiert, ich muss dies für alle Datumsfelder in der App tun, sie könnten start_date, end_date, term_date, finish_date, date usw. heißen. Wie überprüfe ich das? Unterklasse für alle Datumsspalten und schreibe dann eine dynamische Methode für jede? –

0

Eine Antwort auf Ihren Kommentar: Sie gemeinsamen Code extrahieren/Funktionalität in Module, die Sie in einer Klasse gehören (Ich glaube, dass mixin genannt wird?), Oder Sie für Unterklassen gehen kann. Ich glaube nicht, dass Unterklasse der Weg zu gehen ist, wenn es nur eine allgemeine Funktionalität ist, die Sie in Ihre Objekte bekommen wollen, und keine echte Erbschaftssituation.

Werfen Sie einen Blick auf this for more info on modules and Ruby.