2014-01-12 7 views
0

메모리에 객체를 저장하고 Dalli로 객체를 캐시하려고하면 이상한 동작이 나타납니다.Dalli : memcached에 직렬화 할 수없는 Ruby 객체를 캐시하려고합니다.

class Infraction << ActiveRecord::Base 
    has_many :infraction_locations 
    has_many :tracked_points, through: :infraction_locations 
end 

class TrackedPoint << ActiveRecord::Base 
    has_many :infraction_locations 
    has_many :infractions, through: :infraction_locations 
end 

class InfractionLocation << ActiveRecord::Base 
    belongs_to :infraction 
    belongs_to :tracked_point 
    belongs_to :rule 
end 

이 작동 :

i = Infraction.create 
i.tracked_points << TrackedPoint.create(location_id: 1) 
i.save 
Rails.cache.write "my_key", i 

를 이것은 또한 작동합니다 (두 번째 경우 바로 TrackedPoint의) 객체가,에 의해 암시 적으로 데이터베이스에 저장됩니다

i = Infraction.new 
i.tracked_points << TrackedPoint.create(location_id: 1) 
i.save 
Rails.cache.write "my_key", i 

공지 것을 생성하라.

나는 또한 i을 다시로드하면 캐시에 개체를 쓸 수 있음을 발견했습니다. 그래서이 작동합니다

i = Infraction.new 
i.tracked_points << TrackedPoint.new(location_id: 1) 
i.save 
i.reload 
Rails.cache.write "my_key", i 

이 실패

i = Infraction.new 
i.tracked_points << TrackedPoint.new(location_id: 1) 
i.save 
Rails.cache.write "my_key", i 

그러나, 나는 몇 가지 이상한 복사로 할 경우, 내가 일을 실패한 예를 얻을 수 있습니다 :

i = Infraction.new 
i.tracked_points << TrackedPoint.new(location_id: 1) 
i.save 
copy = i.dup 
copy.tracked_points = i.tracked_points.to_a 
Rails.cache.write "my_key", copy 

을 내 실패의 예에서 , 데이터베이스에 저장하기 전에 다음과 같이 위반 (i)을 캐시 할 수 있습니다.

i = Infraction.new 
i.tracked_points << TrackedPoint.new(location_id: 1) 
Rails.cache.write "what", i 

데이브 (Dave)의 생각에 따라 TrackedPoint의 경우 << 대신 build을 시도하고 accepts_nested_attributes_for :tracked_pointsInfraction으로 추가했지만 시도한 것은 없습니다.

나는 로그에 마샬링/시리얼 오류가 점점 오전 :

You are trying to cache a Ruby object which cannot be serialized to memcached. 

나는 또한 레일 3.2.13 및 크루즈 2.7.0

편집

페이지를 실행하고 있습니다 : Cacheing an ActiveRecord Object that has_many through:

답변

0

squeel의 문제였습니다.

마샬링되지 않은 AliasTracker라는 것이 있습니다.이 문제를 해결하기 위해 나타납니다 원숭이 패치는 다음과 같습니다

module ActiveRecord 
    module Associations 
    class AliasTracker 
     def marshal_dump(*) 
     nil 
     end 

     def marshal_load(*) 
     nil 
     end 
    end 
    end 
end 

토론과 대답 여기에서 더 많은 : 아이디어에 대한 https://github.com/activerecord-hackery/squeel/issues/232

0

코드 차이 만 살펴 보는 것이 가장 좋습니다.

처음 두 예제에서는 TrackedPoint.create를 사용하여 연결된 개체를 만들어 데이터베이스에 즉시 보관합니다. 따라서 "< <"을 통한 연결 지정은 해당 개체에 대한 ID가 있으므로 작동합니다.

세 번째 항목에서는 TrackedPoint.new를 사용하고 개체를 할당합니다. 이는 중첩 된 생성을 활용합니다. 따라서 모델에 "accepts_nested_attributes_for"가 필요합니다. 적절한 방법 IIRC는 "build"를 사용하여 새로운 객체의 연관성을 적절하게 인스턴스화합니다. 내 생각 엔 레일즈가 TrackedPoint 객체를 만드는 곳에서 dup 한 이상한 케이스를 보았습니다. 더 이상 중첩 된 속성 케이스가 아니므로 기존 객체를 연결에 직접 할당하는 것입니다.

+0

감사합니다,하지만 난 같은 결과를 얻을. 위반을 다시로드하면 개체를 캐시에 저장할 수 있습니다. 더 많은 예제로 내 질문을 업데이트했습니다. –

+0

클래스에 사용자 정의 _dump 및 _load 메소드를 작성해야 할 수도 있습니다. 마샬 박사. "클래스에 특별한 직렬화가 필요한 경우 (예를 들어 특정 형식으로 직렬화하려는 경우) 또는 그렇지 않으면 직렬화 할 수없는 객체가 포함되어있는 경우 자체 직렬화 전략을 구현할 수 있습니다." – engineerDave