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ì?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top