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.

YAML, ActiveRecord Serialize and Date formats problem

#340

I'm spanish, and was using DATE_FORMATS to allow correct spanish format of date values. I'm using this at environment.rb file:

ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS[:default] = '%d-%m-%Y'

But using serialize of attributes in ActiveRecord classes give me problems. I have a simple model like that:

class History < ActiveRecord::Base serialize :changes end

Doing this:

History.create({:changes=>{:my_date=>Date.today}})

I can't read changes attribute like an Hash object, it always return a String object.

Digging deeper,..., I have found that the problem resides on the YAML library and the format of Date type.

Doing this:

Date.today.to_yaml => "--- !timestamp 05-06-2008\n"

But doing this:

YAML.load(Date.today.to_yaml) ArgumentError: argument out of range

    from /usr/lib/ruby/1.8/yaml.rb:133:in `utc'
    from /usr/lib/ruby/1.8/yaml.rb:133:in `node_import'
    from /usr/lib/ruby/1.8/yaml.rb:133:in `load'
    from /usr/lib/ruby/1.8/yaml.rb:133:in `load'
    from (irb):1

Reading the YAML Cookbook at http://yaml4r.sourceforge.net/co... I have found that YAML needs Date to be represented by its year, month and day in ISO8601 order.

¿Why in Rails the YAML/Serialize method don't uses my date format?

Reported by railsgeek · June 5th, 2008 @ 01:39 PM

State: stale
Milestone: none
Assigned to: nobody
Importance: none

Activity

  1. josh
    josh
    • State changed from new to stale
    • Tag set to activerecord, activesupport, bug, yaml

    Closing this ticket as stale. If this is still an issue for you, feel free to reopen this ticket or create a new one with an updated description. Remember those unit tests too ;)

    July 17th, 2008 @ 02:13 AM

  2. Ivan Vanderbyl
    Ivan Vanderbyl

    I have the same issue serialising a hash containing a Date object and can confirm that when running this in console: Date.today.to_yaml => "--- !timestamp 02/04/2009\n"

    and again in irb Date.today.to_yaml => "--- 2009-02-04\n"

    Is this something to do with Rails locals?

    February 4th, 2009 @ 03:54 AM

  3. Andy Lowry
    Andy Lowry

    I think I know what's going on here and how to fix it. The problem is that rails redefines Date.to_s (somewhere - haven't actually found it, or perhaps didn't understand what I was looking at) so it takes an optional first argument that selects a named formatting option from those defined in:

    ActiveSupport::CoreExtensions::Date::Conversion::DATE_FORMATS
    

    If you create an entry in that table with key ":default" it will end up being used by Date.to_s when you don't supply an argument. And the YAML module, understandably (as it is independent of Rails), uses Date.to_s in this fashion. So when you add a :default date format, you actually alter the standard Date class behavior, and you will likely break YAML support for Date objects.

    You can fix this with this bit of code (and if I've got this right, something like this should make its way into the Rails codebase):

    class Date                    # reopen Date class
      def to_yaml( opts={} )      # modeled after yaml/rubytypes.rb in std library
        YAML::quick_emit( self, opts ) do |out|
          out.scalar( "tag:yaml.org,2002:timestamp", self.to_s(:db), :plain )
        end
      end
    end
    

    This uses the already-defined :db format which happens to be exactly what YAML needs (probably a bit safer to define a separate :yaml format that just happens to be identical to the :db format rather than exploiting this coincidence).

    This explains Ivan's observation, that YAMLing dates works just fine in a vanilla irb.

    August 5th, 2009 @ 10:56 PM

  4. Andy Lowry
    Andy Lowry
    • Tag changed from activerecord, activesupport, bug, yaml to activerecord, activesupport, bug, patch, yaml

    Submitting a patch to fix this bug

    August 6th, 2009 @ 05:20 AM

  5. Jason Langenauer
    Jason Langenauer

    I'd like to +1 this patch - I've just run into this problem as well.

    September 7th, 2009 @ 05:28 AM

  6. Tom Brice
    Tom Brice

    +1 to the patch. I found this ticket because the bug described here causes a model that has :serialize column to break if the column contains something with a Date object.

    I applied the patch as a monkey patch and it seem to work. Thanks Andy. I would think this could be added to 2-3-stable fairly easily

    April 23rd, 2010 @ 04:40 PM

  7. Austin Taylor
    Austin Taylor

    +1 I ran into this today.

    June 8th, 2010 @ 09:04 PM

  8. Neeraj Singh
    Neeraj Singh

    I am not able to reproduce this problem with 2-3-stable.

    >> User.create({:changes=>{:my_date=>Date.today}})
      User Create (0.5ms)   INSERT INTO "users" ("name", "created_at", "updated_at", "changes") VALUES(NULL, '2010-06-25 21:21:37', '2010-06-25 21:21:37', '--- 
    :my_date: 2010-06-25
    ')
    => #<User id: 1, name: nil, changes: {:my_date=>Fri, 25 Jun 2010}, created_at: "2010-06-25 21:21:37", updated_at: "2010-06-25 21:21:37">
    >> u = User.first
      User Load (0.8ms)   SELECT * FROM "users" LIMIT 1
    => #<User id: 1, name: nil, changes: {:my_date=>Fri, 25 Jun 2010}, created_at: "2010-06-25 21:21:37", updated_at: "2010-06-25 21:21:37">
    >> u.changes
    => {:my_date=>Fri, 25 Jun 2010}
    
    ActiveRecord::Schema.define(:version => 20100625210553) do
    
      create_table "users", :force => true do |t|
        t.string   "name"
        t.text     "changes"
        t.datetime "created_at"
        t.datetime "updated_at"
      end
    
    end
    class User < ActiveRecord::Base
      serialize :changes
    end
    

    June 25th, 2010 @ 10:23 PM

  9. Josh Partlow
    Josh Partlow
    • Importance changed from to

    This still seems to be an issue in Rails 2.3.8 if you select a :default format which YAML doesn't like:

    jpartlow@fookito:~/dev/glatisant/test-2.3.8$ script/console
    Loading development environment (Rails 2.3.8)
    >> d = Date.today
    => Tue, 24 Aug 2010
    >> s = d.to_yaml
    => "--- 2010-08-24\n"
    >> YAML.load(s)
    => Tue, 24 Aug 2010
    >> ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(:default => '%B %d, %Y')
    => {:db=>"%Y-%m-%d", :short=>"%e %b", :number=>"%Y%m%d", :long=>"%B %e, %Y", :long_ordinal=>#<Proc:0xb755c988@/usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/core_ext/date/conversions.rb:11>, :default=>"%B %d, %Y", :rfc822=>"%e %b %Y"}
    >> s = d.to_yaml
    => "--- !timestamp August 24, 2010\n"
    >> YAML.load(s)
    ArgumentError: argument out of range
    from /usr/lib/ruby/1.8/yaml.rb:133:in `utc'
    from /usr/lib/ruby/1.8/yaml.rb:133:in `node_import'
    from /usr/lib/ruby/1.8/yaml.rb:133:in `load'
    from /usr/lib/ruby/1.8/yaml.rb:133:in `load'
    from (irb):6
    

    August 24th, 2010 @ 10:18 PM

  10. csommerauer (at outfarm)
    csommerauer (at outfarm)

    +1 for this patch. This is still an issue in 2.3.8

    October 13th, 2010 @ 12:09 PM

  11. Brian Landau
    Brian Landau

    +1 for this patch, I'm still seeing this issue in 2.3.10 when using ActiveRecord to serialize a has with a date object.

    November 2nd, 2010 @ 03:07 PM

  12. crazyDiamond
    crazyDiamond

    @Andy Lowry... thank you for the Date patch. I was working on a rake task to backup and reload data and this came in very handy.

    March 24th, 2011 @ 02:39 PM