복붙노트

[RUBY-ON-RAILS] 레일 3.1 Rails.cache 오류 - 형식 오류 : 기본적 proc 디렉토리와 해시를 덤프 할 수 없습니다

RUBY-ON-RAILS

레일 3.1 Rails.cache 오류 - 형식 오류 : 기본적 proc 디렉토리와 해시를 덤프 할 수 없습니다

I는 3.1.0.rc4 (루비 1.9.2p180 (2011-02-18 수요일 수정 30,909) x86_64에-darwin10])에 Rails.cache 방식의 문제로 실행. 코드는 2.3.12에서 동일한 응용 프로그램 내에서 잘 작동 (루비 1.8.7 (2011-02-18 패치 레벨 334)는 i686 - 리눅스], MBARI 0x8770, 루비 엔터 프라이즈 에디션 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>'

나는 사용하여 시도했다 : 대안으로 원 => 진정한 옵션을하지만, Rails.cache.fetch 블록 캐시 객체를 시도하기 때문에 그 작동하지 않습니다.

어떤 제안? 사전에 감사합니다!

해결법

  1. ==============================

    1.이 자세한 조금있을 수 있지만 내가 어떻게 캐싱 내부 작업을 배우고 레일 소스 코드와 함께 시간을 보내고 있었다. 일을 작성하는 것은 아래로 가지 작업이 해치지 않을 수있는 방법에 대한 몇 가지 메모를 공유 나의 이해와 나는 그림을 도움이됩니다. 당신은 서둘러에 있다면 끝으로 건너 뜁니다.

    이 자세한 조금있을 수 있지만 내가 어떻게 캐싱 내부 작업을 배우고 레일 소스 코드와 함께 시간을 보내고 있었다. 일을 작성하는 것은 아래로 가지 작업이 해치지 않을 수있는 방법에 대한 몇 가지 메모를 공유 나의 이해와 나는 그림을 도움이됩니다. 당신은 서둘러에 있다면 끝으로 건너 뜁니다.

    이 ActiveSupport 내부의 기분을 상하게 방법입니다 :

    def should_compress?(value, options)
      if options[:compress] && value
        unless value.is_a?(Numeric)
          compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
          serialized_value = value.is_a?(String) ? value : Marshal.dump(value)
          return true if serialized_value.size >= compress_threshold   
        end
      end
      false  
    end
    

    serialized_value에 할당합니다. 당신이 cache.rb 내부의 주위에 찌를 경우, 당신은 그들이 직렬화 객체에 다시 다음 원수를 캐시에 가서 전에 바이트 문자열로 직렬화 객체에 원수를 사용하고 있음을 알 수 있습니다. 압축 문제는 중요한 것은 원수의 사용이다, 여기에서 중요하지 않습니다.

    문제는이다 :

    어떤 것들은 원수로 직렬화 할 수없는 상태 (예 : OS의 파일 기술자 또는 블록 등)이있다. 당신이 주목하고있는 오류는 이것이다 :

    모델의 누군가가 해시 인 인스턴스 변수를 가지고 있으며, 그 해시 공급 기본값으로 블록을 사용 그래서. column_methods_hash 방법은 이러한 해시를 사용하며, 심지어 @dynamic_methods_hash 내부 해시 캐시; column_methods_hash은 respond_to 공공 방법으로 (간접적으로) 호출됩니다? 그리고 method_missing.

    respond_to 하나? 또는 method_missing 아마 조만간 모든 AR 모델 인스턴스에 전화를하거나 메소드를 호출하면 객체가 unserializable하게 얻을 것이다. 그래서, AR 모델 인스턴스는 레일 3 본질적으로 unserializable 있습니다.

    흥미롭게도의 respond_to? 및 2.3.8에서 method_missing 구현은 디폴트 값의 블록을 사용하는 해시에 의해 뒷받침된다. 2.3.8 캐시는 "[...]는 캐시 문자열을 의미한다"입니다. 그래서 당신은 전체 개체를 처리 할 수있는 백엔드와 운이지고 있었다 또는 객체가 해시와-발동 그들 있었다 전에이 원수를 사용; 또는 아마도 당신은 MemoryStore 캐시 백엔드를 사용했고, 그것은 조금 더 큰 해시 이상입니다.

    여러 범위를-- 람다와 함께 사용하여 AR 오브젝트에 프로세서 수를 저장 끝낼 수 있습니다; 나는 람다 클래스 (또는 싱글 톤 클래스)이 아닌 객체를 저장할 수 있지만 내가 respond_to의 문제로 분석 귀찮게하지 않았다 기대? 그리고 method_missing는 범위의 문제가 관련이 있습니다.

    나는 당신이 당신의 캐시에 잘못된 일을 저장하고 운이지고있어 생각합니다. 당신도 제대로 (즉, 저장하는 간단한 생성 된 데이터가 아닌 전체 모델) 레일 캐시를 사용할 수 있습니다 또는 원수에 설명 된대로 당신은 marshal_dump / marshal_load 또는 _dump / _load 방법을 구현할 수 있습니다. 다른 방법으로는 서버 프로세스 당 하나의 별개의 캐시에 자신을 MemoryStore 백엔드 중 하나를 사용하여 제한 할 수 있습니다.

    당신이 처리 할 준비하지 않는 한 당신은 액티브 모델을 저장에 의존 할 수없는 것은 레일 캐시에있는 오브젝트 자신을 정렬 화하거나 MemoryStore 캐시 백엔드에 자신을 제한하려는.

    문제의 정확한 소스는 레일의 최신 버전에서 변경했지만 해시와 관련된 default_procs의 많은 경우는 여전히 존재한다.

  2. ==============================

    2.덕분에 뮤입니다 - 너무 짧은 그의 뛰어난 분석. 이걸로 이제 직렬화에 내 모델을 얻을 관리했습니다 :

    덕분에 뮤입니다 - 너무 짧은 그의 뛰어난 분석. 이걸로 이제 직렬화에 내 모델을 얻을 관리했습니다 :

    def marshal_dump
      {}.merge(attributes)
    end
    
    def marshal_load stuff
      send :initialize, stuff, :without_protection => true
    end
    

    또한 AS 예를 들어, 사용하여 쿼리 조인 직접 SQL에 의해 약간의 "가상 속성"세트가 DISTINCT 게시물을 선택합니다. *, INNER 게시물 FROM AUTHOR_NAME AS 저자의 이름 난 후, 각각에 대한 attr_accessor를 선언 덤프 /도를로드해야 작업이 들어 author.post_id = posts.id WHERE posts.id = 123 저자 가입 그래서 같은 :

    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
    

    사용 레일 3.2.18

  3. ==============================

    3.어디서 또는 어떤 범위를 사용하는 액티브 :: 관계 개체를 만든 것을 깨달았다. 나는 그 간단한 일을하는 Model.find이 일 것으로 나타났습니다. 나는 일반 배열로 변환을 강제 있도록이 액티브 :: 관계 객체처럼하지 않았다 의심 것을 나를 위해 일했다.

    어디서 또는 어떤 범위를 사용하는 액티브 :: 관계 개체를 만든 것을 깨달았다. 나는 그 간단한 일을하는 Model.find이 일 것으로 나타났습니다. 나는 일반 배열로 변환을 강제 있도록이 액티브 :: 관계 객체처럼하지 않았다 의심 것을 나를 위해 일했다.

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

    4.당신이 그것을 변경 완료 후 바로 기본 시저를 제거합니다. 뭔가 같은 :

    당신이 그것을 변경 완료 후 바로 기본 시저를 제거합니다. 뭔가 같은 :

    your_hash.default = nil # clear the default_proc
    
  5. from https://stackoverflow.com/questions/6391855/rails-cache-error-in-rails-3-1-typeerror-cant-dump-hash-with-default-proc by cc-by-sa and MIT license