2010-09-07 4 views
1

Grettings!Le rappel after_find est rompu après la mise à niveau vers rails3

Dans une application qui fonctionnait parfaitement dans Rails 2.3.8 i ont la méthode de classe suivante:

def self.encode(*attr_names) 
    encoder = Encoder.new(attr_names) 
    before_save encoder 
    after_save encoder    
    after_find encoder 
    define_method(:after_find) { } # defining here, since there's only alias in the Encoder class itself    
end 

Cette méthode fait référence à la classe de codeur. Voici ce:

class Encoder 
    include Encodings 

    def initialize(attrs_to_manage) # We're passed a list of attributes that should be stored encoded in the database 
    @attrs_to_manage = attrs_to_manage 
    end 

    def before_save(model) # Before saving or updating, encode the attributes to their original encoding 
    @attrs_to_manage.each do |field| 
     model[field] = to_orig_encod(model[field]) 
    end 
    end 

    def after_save(model) # After saving, encode them back to utf8 
    @attrs_to_manage.each do |field| 
     model[field] = to_utf8(model[field]) 
    end 
    end 

    alias_method :after_find, :after_save # Do the same after finding an existing record 
end 

Avant la mise à niveau rails3 tous les callbacks (before_save, after_save, after_find) a bien fonctionné. Après la mise à niveau before_save et after_save encore du travail, mais after_find ne fonctionne pas et je reçois l'avertissement deprecation suivant dans mon journal:

DEPRECATION WARNING: Base#after_find has been deprecated, please use Base.after_find :method instead 

Je suis incertain comment changer mon code afin de re -enable la fonctionnalité du rappel after_find. J'ai essayé quelques alternances simples sans succès et la documentation de l'API rails sur ce rappel est très limitée et sans exemples d'implémentation.

Toute aide appréciée, merci d'avance!

Edit:

est ici la solution:

D'accord, il semble donc que le problème était plus subtil qu'il n'y paraît d'abord. Après des tests supplémentaires, j'ai découvert qu'en fait, comme Jeppe l'a souligné, le callback after_find fonctionne indépendamment de l'avertissement de désapprobation, la méthode "to_utf8" a en effet été appelée et exécutée sur les attributs du modèle. La raison pour laquelle le résultat ne correspond pas aux attentes était la méthode "to_utf8" elle-même. Ce qu'il fait est d'utiliser le module ruby ​​Iconv pour convertir des chaînes de codage non-utf8 comme cp1251 par exemple à utf. Cela a été fait pour les attributs d'un modèle récupéré avec Active Record à partir d'une base de données héritée distante avec un codage non-utf. Cependant, comme il s'est avéré, contrairement aux versions précédentes de rails, AR dans les rails 3 automagiquement et gère silencieusement la conversion en ut8 de tous les objets, même ceux récupérés à partir de DB qui ne sont pas unicode. Donc, essentiellement après la mise à niveau, mon code a fini par être reconverti en chaînes utf8 qui ont déjà été converties en utf8 par AR et le résultat a été un tas de caractères charabia. Le problème a été résolu en supprimant complètement les callbacks after_find et after_save, car ils ne sont plus nécessaires dans ce cas :)

Répondre

2

J'ai essayé de reproduire votre problème, mais je ne peux reproduire que l'avertissement de dépréciation, que vous pouvez obtenir débarrasser de en supprimant votre

define_method(:after_find) { } 

déclaration.

Tout semble fonctionner comme prévu, avec et sans l'instruction define_method.

Mon code:

class Testmodel < ActiveRecord::Base 

    def self.encode(*attr_names) 
    encoder = Encoder.new(attr_names) 
    before_save encoder 
    after_save encoder    
    after_find encoder 
    end 
end 

class Encoder 
    def initialize(attrs_to_manage) # We're passed a list of attributes that should be stored encoded in the database 
    @attrs_to_manage = attrs_to_manage 
    end 

    def before_save(model) # Before saving or updating, encode the attributes to their original encoding 
    @attrs_to_manage.each do |field| 
     model[field] = to_orig_encod(model[field]) 
    end 
    end 

    def after_save(model) # After saving, encode them back to utf8 
    @attrs_to_manage.each do |field| 
     model[field] = to_utf8(model[field]) 
    end 
    end 

    alias_method :after_find, :after_save # Do the same after finding an existing record 

    private 
    def to_orig_encod(var) 
    "foo" 
    end 

    def to_utf8(var) 
    "bar" 
    end 
end 

Test Console:

ruby-1.9.2-p0 > Testmodel.create 
=> #<Testmodel id: 3, name: nil, created_at: "2010-09-08 14:02:06", updated_at: "2010-09-08 14:02:06"> 
ruby-1.9.2-p0 > Testmodel.last 
=> #<Testmodel id: 3, name: nil, created_at: "2010-09-08 14:02:06", updated_at: "2010-09-08 14:02:06"> 
ruby-1.9.2-p0 > Testmodel.encode('name') 
=> [Testmodel(id: integer, name: string, created_at: datetime, updated_at: datetime)] 
ruby-1.9.2-p0 > Testmodel.last 
=> #<Testmodel id: 3, name: "bar", created_at: "2010-09-08 14:02:06", updated_at: "2010-09-08 14:02:06"> 

J'avons consulté la documentation à http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html pour comprendre votre question :-)

+0

Cela fait beaucoup d'effort de vous , merci beaucoup pour avoir reproduit le code, je vais jouer avec votre code et celui de ma mine pendant un moment maintenant pour comprendre pourquoi votre code fonctionne et le mien ne l'est pas et je serai de retour avec les conclusions ortly! Merci encore une fois d'avoir pris le temps et l'effort de creuser dans ce domaine! – svilenv

+0

ok, donc j'ai pensé quel était le problème. J'ai expliqué tout cela comme une modification à la question, car il n'y a pas assez d'espace pour tout mettre dans un commentaire. Merci encore, Jeppe, pour avoir revérifié le code et pointé dans la bonne direction! – svilenv

Questions connexes