3

ActiveRecord モデルの動作を拡張するプロジェクト用のメソッドを作成しました。そのほとんどを削除しました。次のコードを検討してください。

class ActiveRecord::Base

  def self.has_translations
    after_initialize :clear_translations_cache

    def clear_translations_cache
      binding.pry
      @_translations = {}
    end
  end
end

基本的に、データベースからインスタンスを取得するときに @_translations インスタンス変数をクリアしたいのです.reloadが、何らかの理由で、データベースから既存のオブジェクトをフェッチした後、データを入力するメソッドを実行してから@_translationsを実行object.reload@_translationsても、同じデータが含まれています。

データベースからオブジェクトを最初にフェッチするときと を呼び出すときに、コールバックが実行されることは確かです.reload。コールバック メソッド内で binding.pry を使用して実行を停止しましたが、何らかの理由self.object_idで内部が元のオブジェクトとは.reload異なるため、元のオブジェクトがクリアされません。object_id@_translations

添付のコンソール出力は次のとおりです。

1.9.3p194 :008 > s = TranslatedItem.first
   76:     def clear_translations_cache
=> 77:       @_translations = {}
   78:     end

[1] pry(#<TranslatedItem>)> self.class
=> TranslatedItem(id: integer, created_at: datetime, updated_at: datetime)
[2] pry(#<TranslatedItem>)> self.object_id
=> 70254243993580
[3] pry(#<TranslatedItem>)> exit
1.9.3p194 :009 > s.object_id
 => 70254243993580
1.9.3p194 :010 > s.reload
   76:     def clear_translations_cache
=> 77:       @_translations = {}
   78:     end
[1] pry(#<ServiceLevel>)> self.class
=> TranslatedItem(id: integer, created_at: datetime, updated_at: datetime)
[2] pry(#<TranslatedItem>)> self.object_id
=> 70254259259120
4

1 に答える 1

8

あなたが見ている動作は、ActiveRecord のリロードの仕組みに関連していると思います。

fresh_object = self.class.unscoped { self.class.find(self.id, options) }
@attributes.update(fresh_object.instance_variable_get('@attributes'))

データベースからオブジェクトを見つけて新しいオブジェクトを作成していることに気付くでしょう。これは、コールバック メソッドで 2 つの異なる object_id 値が表示される理由を説明しています。リロード中に初期化されるオブジェクトは、その属性にのみ使用され、その後スコープ外になります。

なぜこのように振る舞ったのか、それとも別の方法を探しているのか、あなたの質問からは明らかではありません。

アップデート:

モデルをリロードするときにインスタンス変数をクリアする方法を探しているだけなら、いくつかのオプションがあります。

1) 明示的に呼び出すことができる独自の reload メソッドを追加します。

class ActiveRecord::Base
  def reload_everything
    reload
    @_translations = {}
  end
end

object.reload_everything

2) リロードの動作を変更する

module ReloadTranslations
  def reload(*args)
    super
    @_translations = {}
  end
end

ActiveRecord::Base.send(:include, ReloadTranslations)
于 2012-09-23T21:34:03.540 に答える