diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | README.md | 10 | ||||
-rw-r--r-- | lib/hashie.rb | 4 | ||||
-rw-r--r-- | lib/hashie/extensions/mash/active_model.rb | 18 | ||||
-rw-r--r-- | lib/hashie/mash.rb | 32 | ||||
-rw-r--r-- | spec/hashie/mash_spec.rb | 11 |
6 files changed, 63 insertions, 15 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 009d593..9869b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Next -* Your contribution here. +* [#146](https://github.com/intridea/hashie/issues/146): Mash#respond_to? inconsistent with #method_missing and does not respond to #permitted? - [@dblock](https://github.com/dblock). +* [#89](https://github.com/intridea/hashie/issues/89): Added Hashie::Extensions::Mash::ActiveModel for compatibility with Rails 4.x Strong Parameters - [@dblock](https://github.com/dblock). ## 2.1.1 (4/12/2014) @@ -238,6 +238,16 @@ p[:awesome] # => NoMethodError p[:occupation] # => 'Rubyist' ``` +### Mash and Rails 4 Strong Parameters + +Add the following initializer in config/initializers/mash.rb when using Mash with [Rails 4 Strong Parameters](http://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters). This prevents Mash from responding to `:permitted?` and therefore triggering an ActiveModel `ForbiddenAttributesProtection` exception. + +```ruby +class Mash + include Hashie::Extensions::Mash::ActiveModel +end +``` + ## Trash A Trash is a Dash that allows you to translate keys on initialization. diff --git a/lib/hashie.rb b/lib/hashie.rb index b889aef..e3443f5 100644 --- a/lib/hashie.rb +++ b/lib/hashie.rb @@ -22,5 +22,9 @@ module Hashie autoload :StringifyKeys, 'hashie/extensions/key_conversion' autoload :SymbolizeKeys, 'hashie/extensions/key_conversion' autoload :DeepFetch, 'hashie/extensions/deep_fetch' + + module Mash + autoload :ActiveModel, 'hashie/extensions/mash/active_model' + end end end diff --git a/lib/hashie/extensions/mash/active_model.rb b/lib/hashie/extensions/mash/active_model.rb new file mode 100644 index 0000000..2c37323 --- /dev/null +++ b/lib/hashie/extensions/mash/active_model.rb @@ -0,0 +1,18 @@ +module Hashie + module Extensions + module Mash + # Extends Mash to behave in a way compatible with ActiveModel. + module ActiveModel + def respond_to?(name, include_private = false) + return false if name == :permitted? + super + end + + def method_missing(name, *args) + fail ArgumentError if name == :permitted? + super + end + end + end + end +end diff --git a/lib/hashie/mash.rb b/lib/hashie/mash.rb index dc01199..34317f9 100644 --- a/lib/hashie/mash.rb +++ b/lib/hashie/mash.rb @@ -57,6 +57,7 @@ module Hashie class Mash < Hash ALLOWED_SUFFIXES = %w(? ! = _) include Hashie::PrettyInspect + alias_method :to_s, :inspect # If you pass in an existing hash, it will @@ -185,11 +186,15 @@ module Hashie self end - # Will return true if the Mash has had a key - # set in addition to normal respond_to? functionality. def respond_to?(method_name, include_private = false) - return true if key?(method_name) || prefix_method?(method_name) - super + return true if key?(method_name) + _, suffix = method_suffix(method_name) + case suffix + when '=', '?', '!', '_' + return true + else + super + end end def prefix_method?(method_name) @@ -199,17 +204,16 @@ module Hashie def method_missing(method_name, *args, &blk) return self.[](method_name, &blk) if key?(method_name) - suffixes_regex = ALLOWED_SUFFIXES.join - match = method_name.to_s.match(/(.*?)([#{suffixes_regex}]?)$/) - case match[2] + name, suffix = method_suffix(method_name) + case suffix when '=' - self[match[1]] = args.first + self[name] = args.first when '?' - !!self[match[1]] + !!self[name] when '!' - initializing_reader(match[1]) + initializing_reader(name) when '_' - underbang_reader(match[1]) + underbang_reader(name) else default(method_name) end @@ -217,6 +221,12 @@ module Hashie protected + def method_suffix(method_name) + suffixes_regex = ALLOWED_SUFFIXES.join + match = method_name.to_s.match(/(.*?)([#{suffixes_regex}]?)$/) + [match[1], match[2]] + end + def convert_key(key) #:nodoc: key.to_s end diff --git a/spec/hashie/mash_spec.rb b/spec/hashie/mash_spec.rb index 920acf4..477ab42 100644 --- a/spec/hashie/mash_spec.rb +++ b/spec/hashie/mash_spec.rb @@ -328,9 +328,9 @@ describe Hashie::Mash do end end - it 'does not respond to an unknown key with a suffix' do + it 'responds to an unknown key with a suffix' do %w(= ? ! _).each do |suffix| - expect(Hashie::Mash.new(abc: 'def')).not_to be_respond_to(:"xyz#{suffix}") + expect(Hashie::Mash.new(abc: 'def')).to be_respond_to(:"xyz#{suffix}") end end @@ -339,7 +339,12 @@ describe Hashie::Mash do end it 'does not respond to permitted?' do - expect(Hashie::Mash.new).not_to be_respond_to(:permitted?) + expect(Hashie::Mash.new).to be_respond_to(:permitted?) + klass = Class.new(Hashie::Mash) do + include Hashie::Extensions::Mash::ActiveModel + end + expect(klass.new).not_to be_respond_to(:permitted?) + expect { klass.new.permitted? }.to raise_error(ArgumentError) end end |