Skip to content

Instantly share code, notes, and snippets.

@michaeldv
Created November 30, 2010 00:10
Show Gist options
  • Save michaeldv/720887 to your computer and use it in GitHub Desktop.
Save michaeldv/720887 to your computer and use it in GitHub Desktop.
Regression between Rails 3.0.3 and 3.0.0
### 1) Added $stderr tracing in gems/activesupport-3.0.3/lib/active_support/xml_mini.rb
###
FORMATTING = {
"symbol" => Proc.new { |symbol| symbol.to_s },
"date" => Proc.new { |date| date.to_s(:db) },
"datetime" => Proc.new { |time| $stderr.puts "3.0.3: time.xmlschema for <#{time.class.inspect}>"; time.xmlschema },
"binary" => Proc.new { |binary| ActiveSupport::Base64.encode64(binary) },
"yaml" => Proc.new { |yaml| yaml.to_yaml }
} unless defined?(FORMATTING)
### 2) Added $stderr tracing in gems/activesupport-3.0.3/lib/active_support/time_with_zone.rb
###
def xmlschema(fraction_digits = 0)
$stderr.puts "3.0.3: xmlschema..."
fraction = if fraction_digits > 0
".%i" % time.usec.to_s[0, fraction_digits]
end
"#{time.strftime("%Y-%m-%dT%H:%M:%S")}#{fraction}#{formatted_offset(true, 'Z')}"
end
### 3) Added the same tracing in gems/activesupport-3.0.0
###
### Now... In Rails 3.0.0 both :created_at and :updated_at are treated as
### <ActiveSupport::TimeWithZone>, so everything is kosher:
###
Loading development environment (Rails 3.0.0)
>> Time.zone = "Pacific Time (US & Canada)"
"Pacific Time (US & Canada)"
>> a = Account.first
Account Load (0.7ms) SELECT `accounts`.* FROM `accounts` WHERE (`accounts`.`deleted_at` IS NULL) LIMIT 1
#<Account:0x00000103afc9c8> {
:id => 1,
:user_id => 8,
:assigned_to => 6,
:name => "Walker-Dare",
:access => "Public",
:website => "http://www.walkerdare.com",
:toll_free_phone => "1-800-879-6613",
:phone => "(252)282-8860",
:fax => "(659)573-1022",
:deleted_at => nil,
:created_at => Tue, 25 May 2010 02:52:26 PDT -07:00,
:updated_at => Tue, 25 May 2010 04:47:39 PDT -07:00,
:email => "info@walkerdare.com",
:background_info => nil
}
>> a.updated_at = Time.now
2010-11-29 15:40:20 -0800
>> a.to_xml
3.0.0: time.xmlschema for <ActiveSupport::TimeWithZone>
3.0.0: xmlschema...
3.0.0: time.xmlschema for <ActiveSupport::TimeWithZone>
3.0.0: xmlschema...
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<account>\n <access>Public</access>\n <assigned-to type=\"integer\">6</assigned-to>\n <background-info nil=\"true\"></background-info>\n <created-at type=\"datetime\">2010-05-25T02:52:26-07:00</created-at>\n <deleted-at type=\"datetime\" nil=\"true\"></deleted-at>\n <email>info@walkerdare.com</email>\n <fax>(659)573-1022</fax>\n <id type=\"integer\">1</id>\n <name>Walker-Dare</name>\n <phone>(252)282-8860</phone>\n <toll-free-phone>1-800-879-6613</toll-free-phone>\n <updated-at type=\"datetime\">2010-11-29T15:40:20-08:00</updated-at>\n <user-id type=\"integer\">8</user-id>\n
### In Rails 3.0.3 however :updated_at is <ActiveSupport::TimeWithZone> but
### :created_at is <Time>, so time.xmlschema invokes default Time.#xmlschema
### (in my case it lives in ~/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/time.rb)
###
Loading development environment (Rails 3.0.3)
>> Time.zone = "Pacific Time (US & Canada)"
"Pacific Time (US & Canada)"
>> a = Account.first
Account Load (0.7ms) SELECT `accounts`.* FROM `accounts` WHERE (`accounts`.`deleted_at` IS NULL) LIMIT 1
#<Account:0x000001049cd970> {
:id => 1,
:user_id => 8,
:assigned_to => 6,
:name => "Walker-Dare",
:access => "Public",
:website => "http://www.walkerdare.com",
:toll_free_phone => "1-800-879-6613",
:phone => "(252)282-8860",
:fax => "(659)573-1022",
:deleted_at => nil,
:created_at => Tue, 25 May 2010 02:52:26 PDT -07:00,
:updated_at => Tue, 25 May 2010 04:47:39 PDT -07:00,
:email => "info@walkerdare.com",
:background_info => nil
}
>> a.updated_at = Time.now
2010-11-29 15:49:18 -0800
>> a.to_xml
3.0.3: time.xmlschema for <Time> ### <--- REGRESSION!
1.9.1: xmlschema... ### <--- Default Time#xmlschema
3.0.3: time.xmlschema for <ActiveSupport::TimeWithZone>
3.0.3: xmlschema...
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<account>\n <access>Public</access>\n <assigned-to type=\"integer\">6</assigned-to>\n <background-info nil=\"true\"></background-info>\n <created-at type=\"datetime\">2010-05-25T09:52:26Z</created-at>\n <deleted-at type=\"datetime\" nil=\"true\"></deleted-at>\n <email>info@walkerdare.com</email>\n <fax>(659)573-1022</fax>\n <id type=\"integer\">1</id>\n <name>Walker-Dare</name>\n <phone>(252)282-8860</phone>\n <toll-free-phone>1-800-879-6613</toll-free-phone>\n <updated-at type=\"datetime\">2010-11-29T15:49:18-08:00</updated-at>\n <user-id type=\"integer\">8</user-id>\n <website>http://www.walkerdare.com</website>\n</account>\n"
---
In gems/ruby-1.9.2-p0@r3/gems/activemodel-3.0.3/lib/active_model/serializers/xml.rb:
def serialize
...
@builder.tag!(*args) do
add_attributes_and_methods
...
end
def add_attributes_and_methods
(serializable_attributes + serializable_methods).each do |attribute|
...
end
def serializable_attributes
attributes_hash.map do |name, value|
self.class::Attribute.new(name, @serializable, value)
end
end
Stay tuned, we are almost there :-)
class Serializer #:nodoc:
class Attribute #:nodoc:
attr_reader :name, :value, :type
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
@value = raw_value || @serializable.send(name) # <--- HERE raw_value preserves its class
### @value = value || @serializable.send(name) # <--- Rails 3.0.0 code
### Rails 3.0.0 was invoking send (since value is not defined), thus converting Time to ActiveSupport::TimeWithZone
###
### Possible fix:
### raw_value = raw_value.in_time_zone if raw_value.respond_to?(:in_time_zone)
###
@type = compute_type
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment