Это происходит главным образом из-за изменений, внесенных в ActiveSupport::HashWithIndifferentAccess
в различных выпусках по мере развития Rails, и в метод default
(не путайте с Hash # default).
Если вы видите в Rails 4 версию ActiveSupport :: HashWithIndifferentAccess, метод по умолчанию будет выглядеть так:
def default(key = nil)
if key.is_a?(Symbol) && include?(key = key.to_s)
self[key]
else
super
end
end
Который явно получает ключ при вызове, проверяет его тип и, если включен в хеш (self) в качестве одного из ключей, возвращает его значение, в противном случае вызывает super.
А в более новых версиях (более новых, потому что ваш пример не работает в версиях Rails 4+) это выглядит так:
def default(*args)
super(*args.map { |arg| convert_key(arg) })
end
def convert_key(key) # :doc:
key.kind_of?(Symbol) ? key.to_s : key
end
Который пытается вернуть каждый элемент из аргументов, переданных по умолчанию, при вызове String, если это символ, или вернуть тот же элемент.
Это в вашем примере вернет nil для default
, что объясняет ошибку KeyError, которую вы получаете.
Ошибка или разница в поведении не %
, а во внесенных изменениях.