Question

J'ai un modèle avec plusieurs attributs de date. Je voudrais pouvoir définir et obtenir les valeurs sous forme de chaînes. J'ai sur-rade sur l'une des méthodes (Bill_Date) comme ainsi:

  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

Cela fonctionne très bien pour mes besoins, mais je veux faire la même chose pour plusieurs autres attributs de date ... comment profiterais-je de la méthode manquante afin que n'importe quel attribut de date puisse être défini / va comme ça?

Était-ce utile?

La solution

Comme vous connaissez déjà la signature des méthodes souhaitées, il pourrait être préférable de les définir au lieu d'utiliser method_missing. Vous pouvez le faire comme ça (à l'intérieur de votre définition de classe):

[: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

Si la répertorié tous les attributs de date n'est pas un problème, cette approche est meilleure car vous traitez avec des méthodes régulières au lieu d'une magie à l'intérieur method_missing.

Si vous souhaitez appliquer cela à tous les attributs qui ont des noms se terminant par _date Vous pouvez les récupérer comme ça (dans votre définition de classe):

column_names.grep(/_date$/)

Et voici method_missing Solution (non testée, bien que la précédente ne soit pas testée non plus):

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

De plus, c'est bien de remplacer respond_to? Méthode et retour true Pour les noms de méthodes, que vous gérez à l'intérieur method_missing (En 1.9, vous devez remplacer respond_to_missing? Au lieu).

Autres conseils

Vous pourriez être intéressé par les actifs AttributeMethods Module (quel enregistrement actif utilise déjà pour un tas de choses), qui est presque (mais pas tout à fait) ce dont vous avez besoin.

En un mot, tu devrais pouvoir faire

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

Ayant fait ça, my_instance.bill_date_human appellerait attribute_human avec att_name défini sur 'bill_date'. ActiveModel gérera des choses comme method_missing, respond_to pour toi. Le seul inconvénient est que ces méthodes humaines existeraient pour toutes les colonnes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top