2009-05-14 3 views
6

ho metodi in tutti i miei modelli che assomigliano a questo:metodi globali in Ruby on modelli rotaie

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

Vorrei avere qualcosa che scrive automaticamente un metodo come questo per ogni campo datetime in ogni modello , qual'è il miglior modo per farlo?

-C

risposta

16

Ho dovuto solo rispondere, perché è un divertente esercizio Ruby.

L'aggiunta di metodi a una classe può essere eseguita in molti modi, ma uno dei modi più accurati consiste nell'utilizzare alcune delle funzioni di riflessione e valutazione di Ruby.

Creare questo file nella cartella lib come 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 

Ora basta includere in tutti i modelli che ne hanno bisogno

class CourseSection < ActiveRecord::Base 
    include DateMethods 
end 

Quando incluso, il modulo esaminerà qualsiasi date colonne e genera i metodi formattati per te.

Scopri come funziona questa roba Ruby. È molto divertente.

Detto questo, è necessario chiedersi se è necessario. Non penso che sia personalmente, ma, di nuovo, è stato divertente scrivere.

-b-

+2

perché utilizzare raccogliere e compattare sulla matrice anziché selezionare? –

+1

Hai ragione. .select sarebbe più appropriato qui. Ho trovato occasioni in cui .collect.compact è più veloce, anche quando sembra non dovrebbe essere, ma in questo caso .select è una scelta molto migliore. Grazie per averlo capito. Mi stavo concentrando sul fare le cose difficili e ho perso le cose facili. –

+0

+1 Cose interessanti e divertenti. Sarebbe meglio se tu correggessi la risposta (qui su SO) per includere i commenti di Chris. –

11

Sembra più qualcosa per un aiuto per me. Prova questo nella guida dell'applicazione:

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

formattazione non è qualcosa che appartiene realmente nel modello (proprio per la ragione che hai scoperto ... mettere tale codice comune in ogni modello è fastidioso)

Se vuoi davvero fare come dici tu, allora quello che potresti fare è monkeypatch della superclasse ActiveRecord e aggiungere la funzione che desideri. Sarebbe quindi disponibile per tutti i tuoi modelli. Fai attenzione che il monkeypatching può portare a comportamenti imprevedibili e indefiniti e usarli a tuo rischio e pericolo! E 'anche abbastanza hacky :)

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

solo bastone che da qualche parte, che sarà eseguito prima di ogni altra cosa nella vostra applicazione sarà, e sarà in modo dinamico aggiungere il metodo alla classe di base dei modelli, rendendolo disponibile per l'uso .

Oppure è possibile creare un mixin per tutti i modelli, ma sembra un po 'eccessivo per un singolo metodo.

+1

+1 da me. Stavo solo scrivendo la stessa risposta ... – tomafro

+0

ok, supponiamo che fosse appropriato inserire la formattazione nel modello o che io voglia fare qualcos'altro oltre alla formattazione con ogni singolo campo della data della mia applicazione, come dovrei farlo? –

+0

sì, ma la parte 'start_date' è hard-coded qui, ho bisogno di fare questo per tutti i campi data nell'app, potrebbero essere chiamati start_date, end_date, term_date, finish_date, date, ecc. Come faccio a controllare sottoclasse per tutte le colonne di date e quindi scrivere un metodo dinamico per ognuna? –

0

Una risposta al tuo commento: è possibile estrarre codice comune/funzionalità in moduli che si include in una classe (I belive che si chiama mixin?) Oppure si può andare per le sottoclassi. Non penso che la sottoclasse sia la strada da percorrere quando si tratta della sua funzionalità solo comune che si vuole ottenere nei propri oggetti, e non una reale situazione di ereditarietà.

Dai uno sguardo allo this for more info on modules and Ruby.