2010-06-30 5 views
3

J'essaie d'implémenter le modèle de chaîne de responsabilité dans Ruby et ActiveRecord pour un objet polymorphe. J'ai quelques problèmes.Problèmes de chaîne de responsabilité et alias_method dans Ruby

  • Parfois, je reçois une erreur qu'une méthode n'est pas définie lorsque je tente de alias_method, je pense que cela est parce que la classe n'est pas chargé ou quelque chose donc je fais un explicity envoyer pour obtenir la méthode
  • Je reçois un tas de chaînes infinies où la fonction aliasée (original_method) appelle la méthode qui appelle original_method. Je me demande si c'est parce que quand vous alias une méthode qui a déjà été écrasée, vous faites essentiellement "original_method" une copie de la méthode aliasée.
  • Je travaille actuellement autour de cela en ayant une fonction comme "chained" retourner une sous-classe de Setting avec toutes les méthodes définies mais curieux de savoir pourquoi il y avait tant de problèmes avec alias_method droit dans la classe.

Voici un exemple:

class Hospital 
    has_one :setting, :as => :settable 
    belongs_to :administrative_area 

    def next_link 
    adminstrative_area 
    end 

    def usable_setting 
    setting ? setting : next_link.usable_setting 
    end 
end 

Ensuite, j'ai un objet Cadre:

class Setting < ActiveRecord::Base 

belongs_to :settable, :polymorphic => true 

def chained 
    %w(api_key active_days).each do |method| 

    # this is here because otherwise the method isn't defined, 
    # it's almost as while it's going up, the metaclass doesn't have the columns 
    # until it loads, probably will be fixed if we cache classes 
    self.send method.to_sym 

    (class << self; self; end).class_eval do 

     define_method method do |*args| 
     alias_method "original_#{method}", method 
     my_setting = send("original_#{method}") 
     if my_setting.nil? or my_setting.empty? 
      settable.next_link.usable_setting.chained.send(method) 
     else 
      return my_setting 
     end 
     end 
    end 
    end 
    self 
end 
end 

Répondre

1

Vous semblez être trop compliquer. On dirait que vous essayez de voir si api_key et active_days existent, et si ce n'est pas le cas, récupérez-le ailleurs.

est ici la bonne façon de le faire, en supposant que api_key et active_days sont des colonnes dans votre table:

class Setting < ActiveRecord::Base 

    belongs_to :settable, :polymorphic => true 

    def api_key 
    super || settable.next_link.usable_setting.api_key 
    end 

    def active_days 
    super || settable.next_link.usable_setting.active_days 
    end 
end 

Vous pouvez refactoriser un peu pour garder la clarté et de supprimer les doublons. Donc, dans ce cas, notez que si vous avez api_key/active_days disponible, il sera retourné. Otehrwise, il ira chercher usable_setting de next_link. Si celui-ci a api_key/active_days, il sera retourné, sinon il récupérera usable_setting de next_link. Etc.

+0

Hey, cette réponse est géniale mais je pense que le principal problème que j'avais était de définir les méthodes métamagiquement. La raison pour laquelle je veux le faire est que j'ai beaucoup de fonctions chaînées et en tant que programmeur, je préfère passer 10 heures à essayer d'éviter la frappe au lieu de 2 heures en tapant tout. J'ai fini par faire En créant une classe séparée qui représentait le chaînage, je pense qu'il était difficile de le faire dans activeecord en raison de la façon dont il crée ses propres fonctions alias. – David

+0

Si vous voulez le faire comme par magie, tout ce que vous avez à faire est: '[: api_key,: active_days] .each {| meth | define_method (meth) {super || next_usable_setting.send (meth)}} '. Mais franchement, je préfère les définir séparément, parce que c'est plus agréable. –

Questions connexes