Bug #9731

Rails' HashWithIndifferentAccess is incompatible with Ruby's keyword arguments

Added by Konstantinos Karachalios 11 months ago. Updated 11 months ago.

[ruby-core:61966]
Status:Open
Priority:Normal
Assignee:-
ruby -v:2.1.1 Backport:2.0.0: UNKNOWN, 2.1: UNKNOWN

Description

Origin: https://github.com/rails/rails/issues/14643

In Ruby it is possible to use a POR Hash in place of keyword arguments, making the transition between using an options = {} to keyword arguments easy.

The same is not true for HashWithIndifferentAccess and this makes it difficult to pass the params hash directly to methods with keyword arguments.

Bug test

require 'active_support/hash_with_indifferent_access'
require 'minitest/autorun'

def sum(a: 0, b: 0)
  a + b
end

class BugTest < MiniTest::Unit::TestCase
  def setup
    @normal_hash = {a: 18, b: 24} # just a hash
    @indiff_hash = ActiveSupport::HashWithIndifferentAccess.new(@normal_hash)
  end

  def test_ruby_hash
    assert_equal 42, sum(@normal_hash)
  end

  def test_hash_with_indifferent_access
    assert_equal 42, sum(@indiff_hash)
  end
end

Workaround

sum(@indiff_args.symbolize_keys)

VERSIONS

  • ruby 2.0.0-p353 & activesupport 4.0.1
  • ruby 2.1.0-p0 & activesupport 4.0.3
  • ruby 2.1.1-p76 & activesupport 4.0.4, 3.2.17

Related issues

Duplicated by Ruby trunk - Bug #9732: Rails' HashWithIndifferentAccess is incompatible with Rub... Rejected 04/11/2014
Duplicated by Ruby trunk - Bug #9733: Rails' HashWithIndifferentAccess is incompatible with Rub... Rejected 04/11/2014
Duplicated by Ruby trunk - Bug #9734: Rails' HashWithIndifferentAccess is incompatible with Rub... Rejected 04/11/2014
Duplicated by Ruby trunk - Bug #9735: Rails' HashWithIndifferentAccess is incompatible with Rub... Rejected 04/11/2014

History

#1 Updated by Yusuke Endoh 11 months ago

  • Duplicated by Bug #9732: Rails' HashWithIndifferentAccess is incompatible with Ruby's keyword arguments added

#2 Updated by Yusuke Endoh 11 months ago

  • Duplicated by Bug #9733: Rails' HashWithIndifferentAccess is incompatible with Ruby's keyword arguments added

#3 Updated by Yusuke Endoh 11 months ago

  • Duplicated by Bug #9734: Rails' HashWithIndifferentAccess is incompatible with Ruby's keyword arguments added

#4 Updated by Yusuke Endoh 11 months ago

  • Duplicated by Bug #9735: Rails' HashWithIndifferentAccess is incompatible with Ruby's keyword arguments added

#5 Updated by Rafael França 11 months ago

Just to be clear this issue is not about HashWithIndifferentAccess, it is about using hash with string keys to be used as keyword arguments (HashWithIndifferentAccess store the keys as strings).

This same script would fail:

require 'minitest/autorun'

def sum(a: 0, b: 0)
  a + b
end

class BugTest < MiniTest::Unit::TestCase
  def setup
    @hash_with_symbol_keys = {a: 18, b: 24}
    @hash_with_string_keys = {'a' => 18, 'b' => 24}
  end

  def test_hash_with_symbol_keys
    assert_equal 42, sum(@hash_with_symbol_keys)
  end

  def test_hash_with_string_keys
    assert_equal 42, sum(@hash_with_string_keys)
  end
end

#6 Updated by Yukihiro Matsumoto 11 months ago

I am negative for the proposal. My opinion is that you should not (or no longer) use strings as keywords.
For transition purpose, ActiveSupport (or something else) can add a method to convert strings keys to symbol keys.

Matz.

#7 Updated by Rafael França 11 months ago

Yes, I agree with you. I'm also not positive to changing keyword arguments to receive even strings and symbols, but I thought OP should request this feature here since it is not Rails specific, as he would have the same behavior with a normal hash using string keys.

As soon we only support Ruby 2.2 we can store the keywords as symbols, but until there, we can't change HashWithIndifferentAccess to use symbols or we are opening Rails applications to receive DDoS attacks.

We already have this method to convert strings keys to symbol keys. It is called symbolize_keys. And in my opinion it is fine to use if you know what is doing. I would never call symbolize_keys in request parameters for example. At least not until my application is running with the new symbol GC.

#8 Updated by Konstantinos Karachalios 11 months ago

I agree with the above comments. Probably waiting for Ruby 2.2 would be the best course of action here.

I will try nevertheless create a workaround by utilising Method#parameters to feed the usual params.slice(*args).symbolize_keys in a clever and unobstructive way. Hints/ideas are welcome.

Also available in: Atom PDF