summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Doubrovkine (dB.) @dblockdotorg <dblock@dblock.org>2014-04-30 20:58:40 -0400
committerDaniel Doubrovkine (dB.) @dblockdotorg <dblock@dblock.org>2014-04-30 20:58:40 -0400
commit6bb94f89891f8035a77a5115880ba9096abfd4f8 (patch)
treee9bfa10e1eb5f68a1b4dc1fa0892a42b6ff946db
parent3cdd44af36ec79bc7540d7ea6c258b802bccf38a (diff)
parent5ac85162db784e4104e0cb701b4241dd1da1754b (diff)
downloadhashie-6bb94f89891f8035a77a5115880ba9096abfd4f8.tar.gz
Merge pull request #147 from dblock/mash-activemodel
Fixed inconsistency between Mash#respond_to? and #method_missing. Added Hashie::Extensions::Mash::ActiveModel for compatibility with Rails 4 Strong Parameters.
-rw-r--r--CHANGELOG.md3
-rw-r--r--README.md10
-rw-r--r--lib/hashie.rb4
-rw-r--r--lib/hashie/extensions/mash/active_model.rb18
-rw-r--r--lib/hashie/mash.rb32
-rw-r--r--spec/hashie/mash_spec.rb11
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)
diff --git a/README.md b/README.md
index e77262c..88fbf13 100644
--- a/README.md
+++ b/README.md
@@ -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