обратный вызов after_find прерван после обновления до rails3 - PullRequest
1 голос
/ 07 сентября 2010

Grettings!

В приложении, которое работало безупречно в Rails 2.3.8, у меня есть следующий метод класса:

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

Этот метод ссылается на класс Encoder. Вот оно:

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

До обновления до rails3 все обратные вызовы (before_save, after_save, after_find) работали нормально. После обновления before_save и after_save все еще работают, но after_find не работает, и в моем журнале появляется следующее предупреждение об устаревании:

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

Я не уверен, как изменить свой код, чтобы снова включить функциональность обратного вызова after_find. Я попробовал несколько простых изменений безуспешно, и документация по rails API для этого обратного вызова очень ограничена и без примеров реализации.

Любая помощь приветствуется, спасибо заранее!

Edit:

Вот решение:

Хорошо, похоже, проблема была более тонкой, чем изначально показалась. После дополнительного тестирования я обнаружил, что на самом деле, как указал Jeppe, обратный вызов after_find работает независимо от предупреждения об устаревании, метод to_utf8 фактически был успешно вызван и выполнен для атрибутов модели. Причиной того, что результат не соответствовал ожиданиям, был сам метод to_utf8. Он использует модуль ruv Iconv для преобразования строк из кодировки не-utf8, например, cp1251, например, в utf. Это было сделано для атрибутов модели, выбранной с помощью Active Record из удаленной устаревшей базы данных с кодировкой не-utf. Однако, как оказалось, в отличие от предыдущих версий рельсов, AR в рельсах 3 автоматически и автоматически выполняет преобразование в ut8 всех объектов, даже тех, которые извлечены из баз данных, которые не являются Unicode. Таким образом, по сути, после обновления мой код в конечном итоге преобразовал в строки utf8, которые уже были преобразованы AR в utf8, и в результате получился беспорядочный набор символов. Проблема была решена путем полного удаления обратных вызовов after_find и after_save, так как в этом случае они больше не нужны:)

1 Ответ

2 голосов
/ 08 сентября 2010

Я пытался воспроизвести вашу проблему, но я могу воспроизвести только предупреждение об устаревании, от которого вы можете избавиться, удалив оператор

define_method(:after_find) { }

.

Кажется, всекроме того, работает как и ожидалось, с оператором define_method и без него.

Мой код:

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

Консольный тест:

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"> 

Я консультировался сДокументация на http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html, чтобы понять ваш вопрос: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...