Usando il metodo mancante nelle rotaie
-
29-10-2019 - |
Domanda
Ho un modello con diversi attributi della data. Vorrei poter impostare e ottenere i valori come stringhe. Ho trascorso troppo uno dei metodi (Bill_Date) in questo modo:
def bill_date_human
date = self.bill_date || Date.today
date.strftime('%b %d, %Y')
end
def bill_date_human=(date_string)
self.bill_date = Date.strptime(date_string, '%b %d, %Y')
end
Questo funziona perfettamente per le mie esigenze, ma voglio fare la stessa cosa per molti altri attributi della data ... come vorrei sfruttare il metodo mancante in modo che qualsiasi attributo della data possa essere impostato/ottenere così?
Soluzione
Come già conosci la firma dei metodi desiderati, potrebbe essere meglio definirli invece di usare method_missing
. Puoi farlo in quel modo (all'interno della tua classe Definizione):
[:bill_date, :registration_date, :some_other_date].each do |attr|
define_method("#{attr}_human") do
(send(attr) || Date.today).strftime('%b %d, %Y')
end
define_method("#{attr}_human=") do |date_string|
self.send "#{attr}=", Date.strptime(date_string, '%b %d, %Y')
end
end
Se elencare tutti gli attributi della data non è un problema, questo approccio è migliore in quanto hai a che fare con metodi regolari invece di un po 'di magia all'interno method_missing
.
Se vuoi applicarlo a tutti gli attributi che hanno nomi che finiscono _date
Puoi recuperarli in questo modo (all'interno della definizione della tua classe):
column_names.grep(/_date$/)
Ed ecco method_missing
Soluzione (non testato, sebbene il precedente non venga testato):
def method_missing(method_name, *args, &block)
# delegate to superclass if you're not handling that method_name
return super unless /^(.*)_date(=?)/ =~ method_name
# after match we have attribute name in $1 captured group and '' or '=' in $2
if $2.blank?
(send($1) || Date.today).strftime('%b %d, %Y')
else
self.send "#{$1}=", Date.strptime(args[0], '%b %d, %Y')
end
end
Inoltre è bello sovrascrivere respond_to?
metodo e ritorno true
Per i nomi dei metodi, che gestisci all'interno method_missing
(In 1.9 dovresti sovrascrivere respond_to_missing?
invece).
Altri suggerimenti
Potresti essere interessato a ActiveModel AttributeMethods
Modulo (che record attivo utilizza già per un mucchio di cose), che è quasi (ma non del tutto) ciò di cui hai bisogno.
In breve, dovresti essere in grado di fare
class MyModel < ActiveRecord::Base
attribute_method_suffix '_human'
def attribute_human(attr_name)
date = self.send(attr_name) || Date.today
date.strftime('%b %d, %Y')
end
end
Dopo averlo fatto my_instance.bill_date_human
chiamerebbe attribute_human
con attr_name impostato su "Bill_date". ActiveModel gestirà cose come method_missing
, respond_to
per te. L'unico aspetto negativo è che questi metodi umani esisterebbero per tutte le colonne.