Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

ActiveRecord marshal dump/load has a different behavior on boolean [rails]

#5381

Step 1: setup

a = Aritcle.new(:some_boolean => false)
a.save
write_to_memcache(a.id, Marshal.dump(a))
b = Marshal.load(read_from_memcache(a.id))

If I do:

b.some_boolean = nil
b.save

the some_boolean is not written back to the DB. DB still remains false.

But:

a.some_boolean = nil
a.save

works perfectly. DB is set to NULL.

Also:

c = Article.find(a.id)
c.some_boolean = nil
c.save

works fine. DB is set to NULL.

I'm not very sure if this is a boolean specific problem, but I'm thinking rails has some private variable to detect if the record is new, and the marshal is screwing it up.

Any hints? This one was a tough nut to crack on production :) Thanks.

Reported by prasanna · August 14th, 2010 @ 07:45 PM

State: invalid
Milestone: none
Assigned to: Aaron Patterson Aaron Patterson
Importance: Low

Activity

  1. prasanna
    prasanna
    • Assigned user set to Aaron Patterson

    I was wondering if this should be a bug report of a ticket?

    August 14th, 2010 @ 07:52 PM

  2. Aaron Patterson
    Aaron Patterson
    • State changed from new to needs-more-info
    • Importance changed from to Low

    I can't seem to reproduce this problem. What database are you using? What version of Rails? Can you share your schema?

    Even better would be if you could supply a small rails app that reproduces the problem. I would really appreciate that! :-D

    I've tried adding the following test to the AR test cases, but cannot reproduce the problem:

    class Booleantest < ActiveRecord::Base; end
    
    def test_saving_after_marshal
      bool = Booleantest.new(:value => false)
      bool = Marshal.load Marshal.dump bool
      bool.value = nil
      bool.save
      bool.reload
      assert_nil bool.value
    end
    

    August 16th, 2010 @ 06:37 PM

  3. prasanna
    prasanna

    DataBase: mysql
    Rails: 2.3.5

    To reproduce it: You have to put the following statement in your after_save handler.

    class Bool
    
      after_save :dumper
    
      def dumper
        $global = Marshal.load Marshal.dump self
      end
    
    end
    
    Bool.new(:value => false).save
    puts $global.value # is false -> OK
    
    $global.value = nil
    $global.save
    puts $global.value # is nil -> OK
    
    $global.reload
    puts $global.value # is false -> BAD
    

    I owe you an apology for not testing Marshal.load Marshal.dump sequence. I was binary-searching the problem and this is what I got it down to. If you need any more info, or if you are unable to reproduce this, feel free to ping me. myprasanna@gmail.com

    August 16th, 2010 @ 08:11 PM

  4. prasanna
    prasanna

    It is probably not a deal-breaker. I am guessing, rails works like this:

    
    @after_save_running = true
    # call the after_save handlers
    @after_save_running = false
    

    And since I dump in the after_save handler, that variable gets dumped as true. The next time I try to save it fails, to do it, thinking the after_save handler is calling a save function, causing recursion. I think you can safely close this.

    Thanks for your time.

    August 16th, 2010 @ 08:21 PM

  5. Aaron Patterson
    Aaron Patterson
    • State changed from needs-more-info to invalid

    November 4th, 2010 @ 10:10 PM

  6. bingbing