web-dev-qa-db-ja.com

Rails 3.1-Rails.cache error in TypeError:ca n't dump hash with default proc

3.1.0.rc4(Ruby 1.9.2p180(2011-02-18リビジョン30909)[x86_64-darwin10])のRails.cacheメソッドで問題が発生しました。コードは、2.3.12(Ruby 1.8.7(2011-02-18パッチレベル334)[i686-linux]、MBARI 0x8770、Ruby Enterprise Edition 2011.03))の同じアプリケーション内で正常に動作します。しかし、アップグレード後にエラーを返し始めました。まだ理由がわかりません。

複数のスコープを持つオブジェクトをキャッシュしようとすると、エラーが発生するようです。

また、スコープの数に関係なく、ラムダを使用するスコープは失敗します。

私はこれらのパターンからの失敗をヒットしました:

Rails.cache.fetch("keyname", :expires_in => 1.minute) do
    Model.scope_with_lambda
end


Rails.cache.fetch("keyname", :expires_in => 1.minute) do
    Model.scope.scope
end

これは私が受け取るエラーです:

TypeError: can't dump hash with default proc
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:627:in `dump'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:627:in `should_compress?'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:559:in `initialize'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:363:in `new'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:363:in `block in write'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:520:in `instrument'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:362:in `write'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:299:in `fetch'
    from (irb):62
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/railties-3.1.0.rc4/lib/Rails/commands/console.rb:45:in `start'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/railties-3.1.0.rc4/lib/Rails/commands/console.rb:8:in `start'
    from /project/shared/bundled_gems/Ruby/1.9.1/gems/railties-3.1.0.rc4/lib/Rails/commands.rb:40:in `<top (required)>'
    from script/Rails:6:in `require'
    from script/Rails:6:in `<main>'

代替として:raw => trueオプションを使用してみましたが、Rails.cache.fetchブロックがオブジェクトをキャッシュしようとしているため、機能しません。

助言がありますか?前もって感謝します!

42
shedd

Mu-is-too-shortの優れた分析に感謝します。これでモデルをシリアル化することができました:

def marshal_dump
  {}.merge(attributes)
end

def marshal_load stuff
  send :initialize, stuff, :without_protection => true
end

また、ASを使用した直接SQL結合クエリによって設定された「仮想属性」もいくつかあります。 SELECT DISTINCT posts.*, name from authors AS author_name FROM posts INNER JOIN authors ON author.post_id = posts.id WHERE posts.id = 123。これらが機能するためには、それぞれにattr_accessorを宣言し、次のようにそれらをダンプ/ロードする必要があります。

VIRTUAL_ATTRIBUTES = [:author_name]

attr_accessor *VIRTUAL_ATTRIBUTES

def marshal_dump
  virtual_attributes = Hash[VIRTUAL_ATTRIBUTES.map {|col| [col, self.send(col)] }]
  {}.with_indifferent_access.merge(attributes).merge(virtual_attributes)
end

def marshal_load stuff
  stuff = stuff.with_indifferent_access
  send :initialize, stuff, :without_protection => true
  VIRTUAL_ATTRIBUTES.each do |attribute|
    self.send("#{attribute}=", stuff[attribute])
  end
end

Rails 3.2.18

5
AlexChaffee

スコープを使用してActiveRecord::Relationオブジェクトを作成したことに気付きました。その後、簡単なModel.findを実行すると効果があることに気付きました。私はそれがActiveRecord::Relationオブジェクトを好きではないのではないかと思ったので、プレーンなArrayへの変換を強制し、それは私のために働いた。

Rails.cache.fetch([self.id, 'relA']) do
  relA.where(
      attr1: 'some_value'
  ).order(
      'attr2 DESC'
  ).includes(
      :rel_1,
      :rel_2
  ).decorate.to_a
end
3
Jonathan Mui

変更が完了したら、デフォルトのプロシージャを削除してください。何かのようなもの:

your_hash.default = nil # clear the default_proc
0
Sagiv Ofek