How to resolve Marshal.dump "no marshal_dump is defined for class Proc" error
Suppose I have a User < ActiveRecord::Base
.
Now, suppose I would like to create a user instance, validate it and store it in t开发者_运维技巧he session if I can not save it.
user = User.new
...
session[:new_user] = user unless user.save
...
Using the ActiveRecord session one might end up with no marshal_dump is defined for class Proc
coming from Marshal.dump
.
Now, what is the best way to resolve such serialization errors (locate the "invalid" Proc
objects) for an object (does not have to be AR in general) ?
Usually it's better to store the user id in the session, not the User
instance itself. This does mean you have to do a db (or memcache) lookup for authenticated requests, but it saves you a ton of headaches around serialization/caching that you'd otherwise have to deal with.
Also, it's not an "invalid" Proc
in some sense. Proc
instances are containers for Ruby code and application state and therefore cannot be serialized, ever.
For this specific case, I would say, store only the attributes
. ActiveRecord::Base#attributes
returns a hash of the attributes stored in the database, so it will almost certainly not contain any Proc
s.
session[:new_user] = user.attributes unless user.save
In general, however, a simple way is to use inspect
on the object you're trying to marshal.
puts obj.inspect
or equivalently
p obj
Usually this will print internal objects, and you can see whether something is a Proc. If you still can't find it and you need to dig deeper, you can inspect all the member variables of the object.
obj.instance_variables.each do |var|
puts "#{var} = #{obj.instance_eval(var).inspect}"
end
I came across this problem when trying to store an unsaved AR object in the session. Since I was dealing with an arbitrary model, I had to store both the class and attributes in the session so that I could rebuild it later. I solved this by saving the class and attributes in the session together:
session[:key] = {:klass => obj.class.to_s, :attributes => obj.attributes}
I could then recreated the object from the session
obj = session[:key][:klass].constantize.new(session[:key][:attributes])
精彩评论