2009-05-14 8 views
6

Mam metod we wszystkich moich modeli, które wyglądają tak:globalne metody w ruby ​​na modelach szyn

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

chciałbym mieć coś, co automatycznie zapisuje metody jak ten dla każdego pola datetime w każdym modelu , jaki jest najlepszy sposób na zrobienie tego?

-C

Odpowiedz

16

Po prostu musiałem odpowiedzieć na to pytanie, ponieważ jest to zabawne ćwiczenie Ruby.

Dodawanie metod do klasy można zrobić na wiele sposobów, ale jednym z najmilszych sposobów jest użycie niektórych funkcji refleksji i oceny Rubiego.

Utwórz ten plik w folderze, lib 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 

Teraz wystarczy umieścić go w dowolnych modeli, które potrzebują go

class CourseSection < ActiveRecord::Base 
    include DateMethods 
end 

Gdy włączone, moduł będzie patrzeć na dowolny kolumn daty i wygeneruj dla Ciebie metody sformatowane.

Dowiedz się, jak działa ten materiał Ruby. To świetna zabawa.

To powiedziawszy, musisz zadać sobie pytanie, czy jest to konieczne. Nie sądzę, żeby to było osobiście, ale znowu było fajnie pisać.

-b-

+2

dlaczego warto używać funkcji zbierania i kompaktowania na macierzy, zamiast wybierać? –

+1

Masz rację. .select byłoby bardziej odpowiednie tutaj. Znalazłem czasy, kiedy .collect.compact jest szybsze, nawet jeśli wydaje się, że nie powinno, ale w tym przypadku .select jest znacznie lepszym wyborem. Dzięki za złapanie tego. Skupiałem się na robieniu trudnych rzeczy i przegapiłem proste rzeczy. –

+0

+1 Ciekawe i zabawne rzeczy. Byłoby lepiej, gdybyś poprawił odpowiedź (tutaj na SO), aby uwzględnić komentarze Chrisa. –

11

Wygląda bardziej jak coś dla pomocnika dla mnie. Spróbuj tego w pomocy danej aplikacji:

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

Formatowanie nie jest coś, co naprawdę należy w modelu (dla właśnie powód pan odkrył ... wprowadzenie takiego wspólnego kodu w każdym modelu jest irytujące)

Jeśli naprawdę chcesz zrobić tak, jak mówisz, to możesz zrobić monkeypatch nadklasę ActiveRecord i dodać tam odpowiednią funkcję. Byłby wtedy dostępny dla wszystkich modeli. Uważaj, że monkeypatching może prowadzić do nieprzewidywalnych i niezdefiniowanych zachowań i używać go na własne ryzyko! Jest to także dość hacky :)

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

Wystarczy trzymać się, że gdzieś, które będą uruchamiane zanim cokolwiek innego w swojej aplikacji będzie, i będzie dynamicznie dodać metodę do klasy bazowej modeli, dzięki czemu jest gotowy do użycia .

Można również utworzyć mixin dla wszystkich modeli, ale wydaje się to nieco przesadą dla jednej metody.

+1

+1 ode mnie. Właśnie napisałem tę samą odpowiedź ... – tomafro

+0

okej, załóżmy, że było właściwe, aby umieścić formatowanie w modelu lub, że chcę zrobić coś innego oprócz formatowania z każdym polem daty w mojej aplikacji, jak mam to zrobić? –

+0

tak, ale część "start_date" jest tutaj zakodowana na stałe, muszę to zrobić dla wszystkich pól daty w aplikacji, mogą one być nazywane data_początkowa, data_końcowa, data_termata, data_końcowa, data itd. Jak mogę sprawdzić podklasa dla wszystkich kolumn daty, a następnie napisać metodę dynamiczną dla każdej z nich? –

0

Odpowiedź na Twój komentarz: Można wyodrębnić wspólny kod/funkcjonalność do modułów, które umieścisz w klasie (wierzę, że jest nazywany wstawek?) Lub można przejść do podklasy. Nie sądzę, że podklasa jest drogą, którą należy przejść, gdy ma do czynienia ze zwykłą funkcjonalnością, którą chcesz dostać do swoich obiektów, a nie prawdziwą sytuacją dziedziczenia.

Spójrz na this for more info on modules and Ruby.

Powiązane problemy