Ruby on rails Rails 3.2.21和Ruby 2.2.0中断Time.zone.parse
在Rails 3.2.21和Ruby 2.2.0p0中,时区解析器被破坏。在Ruby 2.1.2中,它运行得很好Ruby on rails Rails 3.2.21和Ruby 2.2.0中断Time.zone.parse,ruby-on-rails,ruby,Ruby On Rails,Ruby,在Rails 3.2.21和Ruby 2.2.0p0中,时区解析器被破坏。在Ruby 2.1.2中,它运行得很好 [1] pry(main)> Time.zone.parse("2015-01-12") NoMethodError: undefined method `year' for nil:NilClass from /Users/user/.rvm/gems/ruby-2.2.0/gems/activesupport-3.2.21/lib/active_support/values
[1] pry(main)> Time.zone.parse("2015-01-12")
NoMethodError: undefined method `year' for nil:NilClass
from /Users/user/.rvm/gems/ruby-2.2.0/gems/activesupport-3.2.21/lib/active_support/values/time_zone.rb:275:in `parse'
现在我知道你可以用
Time.parse(“2015-01-12”).localtime来代替它,但这会破坏我应用程序的功能。有任何已知的修复方法吗?所以,这是您最初的情况:
class Dog
def do_stuff(x, y=2)
puts x + y
end
end
d = Dog.new
d.do_stuff(1)
--output:--
3
但是,do_stuff()的代码已经更改,现在您面临类似的问题:
class Dog
def do_stuff(x, y=nil)
puts x + y
end
end
d = Dog.new
d.do_stuff(1)
--output:--
1.rb:4:in `+': nil can't be coerced into Fixnum (TypeError)
from 1.rb:4:in `do_stuff'
from 1.rb:10:in `<main>'
根据rails文档,返回一个对象,因此该类定义了parse()
,这是您想要别名的方法。因此,代码如下所示:
class Timezone #Re-open the Timezone class.
alias_method :orig_parse, :parse #Create an additional name for parse().
def parse(str, now=now()) #Now, redefine parse().
orig_parse(str, now) #Call the original parse() method.
end
end
然后,您可以像往常一样调用parse():
Time.zone.parse("2015-01-12")
我想你应该把代码放在app/helpers/application\u helper.rb
中。看看这是否有效
我认为上面的代码将被视为一种
适配器模式
。尽管如此,因为这个插件已经适合了——它只是不能产生你想要的结果——它可能被认为是一个装饰器模式。因此,现在您可以在简历上注明在rails代码中使用自定义适配器和/或装饰器模式 TLDR:rails bug已经修复,3.2分支上的第一个修复版本是3.2.22
Ruby 2.2更改了在名称不明确时解析默认参数的方式:
def now
...
end
def foo(now = now)
end
在较早版本的ruby中,调用foo
而不使用参数会导致参数now
被设置为now()
方法调用的任何值。在ruby 2.2中,它将改为nil(并且您会得到一个关于循环引用的警告)
您可以通过执行以下任一操作来解决歧义:
def foo(now = now())
end
或
(显然,这一论点的用法正在改变)
显然,它过去的工作方式一直是一个bug。Rails有几个地方依赖这种不良行为,包括在AS::Timezone.parse中。该修复是针对3-2-stable分支的,并最终作为3.2.22的一部分发布
修复此问题的commit to rails有一个指向ruby bug的链接,该ruby bug是关于这个扩展答案的,因为在ActiveSupport::TimeZone类中定义了parse
方法,所以您可以简单地打开它并相应地进行此微小更改
您可以将其放置在config/initializers/timezone.rb下,或参考其他位置来调整此速度
class ActiveSupport::TimeZone
alias_method :orig_parse, :parse #Create an additional name for parse().
def parse(str, now=now()) #Now, redefine parse().
orig_parse(str, now) #Call the original parse() method.
end
end
复杂的问题:ruby 2.1.5和2.2甚至没有Time.zone()
方法。有一个zone()
实例方法,它的源代码在ruby 2.1.5和2.2之间发生了变化。不过,这是一些无法辨认的C代码。我不知道rails是否在其Time.zone()方法中使用了ruby的#zone方法。我在翻阅activesupport的源代码,似乎在2.1.2中使用的行def parse(str,now=now)
现在在2.2.0中的右边now
求值为零。在最新的activesupport主分支中,它现在更具体地被定义为def parse(str,now=now())
,但这似乎是一个重大的突破性变化。好的,很好的侦查。请参阅我的答案,了解您可以做些什么。因为您描述了一个很好的解决方案,我认为在没有可用修复程序的情况下应该使用它(在本例中取消与稳定的3.2分支的链接)从Rails 3.2.22开始,commit现在已经发布:如果您使用的Rails版本不清楚是否已对其进行了后端口修复(在我的例子中是4.1),那么这是一个实用的解决方案。
def foo(something = now)
end
class ActiveSupport::TimeZone
alias_method :orig_parse, :parse #Create an additional name for parse().
def parse(str, now=now()) #Now, redefine parse().
orig_parse(str, now) #Call the original parse() method.
end
end