使用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/time_zone.rb:275:in `parse'
现在我知道您可以将其替换为Time.parse("2015-01-12").localtime
,但这会破坏我的应用中的功能。是否有任何已知的修复方法?
答案 0 :(得分:6)
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
或者
def foo(something = now)
end
(显然改变了对那个论点的用法)
显然它以前的工作方式一直都是一个错误。 Rails有一些地方依赖这种不良行为,包括在AS :: Timezone.parse中。该修正是backported到3-2稳定分支,并最终作为3.2.22的一部分发布。
修复此问题的rails master的提交链接指向有关此内容的ruby错误
答案 1 :(得分:2)
所以,这是你最初的情况:
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>'
抨击!@#$!@#$!@#$!@#$!@#@#developers !!!
在ruby中,您可以使用alias_method()
为方法创建其他名称:
class Dog #Reopen the previously defined Dog class.
alias_method :orig_do_stuff, :do_stuff #Create additional name for do_stuff()
#Now redefine do_stuff():
def do_stuff(x, y=2) #Use a better default value for y.
orig_do_stuff(x, y) #Call the original method.
end
end
d.do_stuff(1)
--output:--
3
根据rails文档,Time.zone()返回一个TimeZone对象,因此这是定义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_helper.rb
里面。看看是否有效。
我认为上述内容将被视为Adapter pattern
。虽然,因为 plug 已经适合 - 它只是不能产生你想要的结果 - 它可能被认为是Decorator pattern
。所以,现在您可以在简历中使用rails代码中的自定义Adapter和/或Decorator模式。 :)
答案 2 :(得分:1)
扩展7stud's答案,因为在ActiveSupport :: TimeZone类中定义了parse
方法,您只需打开它并相应地进行轻微更改。
您可以将其放在config/initializers/timezone.rb
下,或者参考this question以获取替代名称。
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