Rails 6 #except incompatible with Hashie::Mash
philipbjorge opened this issue · 7 comments
I wasn't really sure where to file this bug so I'm putting it here and rails core.
Steps to reproduce
foo = Hashie::Mash.new(x: 1, y: 2)
foo.except(:x)
# => {"x"=>1, "y"=>2}
This is a change in behavior from rails 5 to 6 related to this change: rails/rails@32db884
Expected behavior
Return a new Hashie object with its :x
key removed.
Actual behavior
Returns a new hash that contains the x
key still
System configuration
Rails version: rails 6.0.0.rc1
Ruby version: ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
Looks legit. Would be helpful to get a failing spec in https://github.com/intridea/hashie/tree/master/spec/integration, we have a few rails-specific ones.
Want to also contribute to https://code.dblock.org/2017/02/24/the-demonic-possession-of-hashie-mash.html ? :)
We generally want things to go way of extensions, but if these are only useful for Mash
, then directly in there. But I bet @michaelherold has a stronger and better educated opinion.
I think at its core, we're running into the issue defined here: #449
This is a different issue. This is related to how we store keys for indifferent access. You expect that the Mash stores the key as :x
but it's really storing the key as 'x'
.
Rails itself works around this problem in ActiveSupport::HashWithIndifferentAccess
by defining its own version of #except
for HashWithIndifferentAccess
that converts the keys to exclude. That they changed the implementation of that method in order to maintain compatibility with the core extension indicates that they changes the semantics of the method.
I really do not want to introduce Rails-specific behavior into Hashie in order to maintain compatibility with Rails' extensions. The only way I would really want to add this is through a Railtie because I don't want the #except
method to exist outside of a Rails environment.
Perhaps a hashie-rails
extension with Rails-specific logic would make sense. But I don't believe it belongs in Hashie proper.
(For other's benefit)
At this time, we're resolving by patching in the previous behavior.
class Hash
def except(*keys)
dup.except!(*keys)
end
end
@michaelherold Is the issue the way the keys are stored or the fact that they switched to using #slice
in their implementation?
Rails 6 switched their implementation of #except
to use slice
@BobbyMcWho you've hit on something there. Thanks for that! I've reviewed your PR and will accept it with some changes.