Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add nested attributes to trustable.

  • Loading branch information...
commit 00b5cd5c323ce34edd01e9ebd88a9b249228cd5f 1 parent 2e10fa3
@unders authored
Showing with 74 additions and 45 deletions.
  1. +24 −11 lib/trusted_keys/trustable.rb
  2. +50 −34 spec/trusted_keys/trustable_spec.rb
View
35 lib/trusted_keys/trustable.rb
@@ -9,6 +9,7 @@ def initialize(options)
@scope = options.fetch(:scope)
@trusted_keys = options.fetch(:trusted_keys)
@untrusted = options.fetch(:untrusted)
+ @nested = options[:nested] || false
self.class.send("attr_accessible", *options.fetch(:keys))
end
@@ -18,18 +19,15 @@ def attributes(params)
params[key.to_sym] || params[key.to_s]
end
- result = sanitize_for_mass_assignment(params)
-
- keys = params.keys.map(&:to_s) - result.keys.map(&:to_s)
-
- unless keys.empty?
- untrusted = @untrusted.keys(:scope => @scope,
- :key => nil,
- :keys => keys)
- raise untrusted if untrusted.present?
+ if @nested
+ {}.tap do |hash|
+ params.each do |key, nested_hash|
+ hash[key] = sanitize(nested_hash)
+ end
+ end
+ else
+ sanitize(params)
end
-
- remove_untrusted_keys(result)
end
def on_scope(attributes)
@@ -44,6 +42,21 @@ def level; @scope.size; end
private
+ def sanitize(params)
+ result = sanitize_for_mass_assignment(params)
+
+ keys = params.keys.map(&:to_s) - result.keys.map(&:to_s)
+
+ unless keys.empty?
+ untrusted = @untrusted.keys(:scope => @scope,
+ :key => nil,
+ :keys => keys)
+ raise untrusted if untrusted.present?
+ end
+
+ remove_untrusted_keys(result)
+ end
+
def remove_untrusted_keys(attributes)
trusted_keys = @trusted_keys.select do |trusted|
trusted.level == (level + 1)
View
84 spec/trusted_keys/trustable_spec.rb
@@ -22,6 +22,7 @@
:controller => "events",
:events => {
:nested_attributes => { "0" => { "_destroy"=>"false",
+ "dangerous" => "remove me",
"start"=>"2012" },
"new_1331711737056" => { "_destroy"=>"false",
"start"=>"2012" } } },
@@ -41,41 +42,18 @@ def options(options_hash)
}.merge(options_hash)
end
- describe "#on_scope" do
- context "level 2" do
- it "returns the hash for that level" do
- t = klass.new(options(:scope => [:post, :comments],
- :trusted_keys => [],
- :keys => [:body]))
- t.on_scope(params[:post]).must_equal(params[:post])
- end
- end
-
- context "level 3" do
- it "returns the hash for that level" do
- t = klass.new(options(:scope => [:post, :comments, :author],
- :trusted_keys => [],
- :keys => [:name]))
- t.on_scope(params[:post]).must_equal(params[:post][:comments])
- end
- end
+ describe "nested attributes" do
+ it "returns nested hash" do
+ post = klass.new(options(:scope => [:events, :nested_attributes],
+ :trusted_keys => [],
+ :nested => true,
+ :keys => [ "start", "_destroy" ]))
- context "level 1" do
- it "not applicable" do
- t = klass.new(options(:scope => [:post],
- :trusted_keys => [],
- :keys => [:body]))
- proc { t.on_scope(params) }.must_raise NoMethodError
- end
- end
-
- context "level 0" do
- it "not applicable" do
- t = klass.new(options(:scope => [],
- :trusted_keys => [],
- :keys => [:body]))
- proc { t.on_scope(params) }.must_raise NoMethodError
- end
+ expected = { "0" => { "_destroy"=>"false",
+ "start"=>"2012" },
+ "new_1331711737056" => { "_destroy"=>"false",
+ "start"=>"2012" } }
+ post.attributes(params).must_equal(expected)
end
end
@@ -176,6 +154,44 @@ def options(options_hash)
end
end
+ describe "#on_scope" do
+ context "level 2" do
+ it "returns the hash for that level" do
+ t = klass.new(options(:scope => [:post, :comments],
+ :trusted_keys => [],
+ :keys => [:body]))
+ t.on_scope(params[:post]).must_equal(params[:post])
+ end
+ end
+
+ context "level 3" do
+ it "returns the hash for that level" do
+ t = klass.new(options(:scope => [:post, :comments, :author],
+ :trusted_keys => [],
+ :keys => [:name]))
+ t.on_scope(params[:post]).must_equal(params[:post][:comments])
+ end
+ end
+
+ context "level 1" do
+ it "not applicable" do
+ t = klass.new(options(:scope => [:post],
+ :trusted_keys => [],
+ :keys => [:body]))
+ proc { t.on_scope(params) }.must_raise NoMethodError
+ end
+ end
+
+ context "level 0" do
+ it "not applicable" do
+ t = klass.new(options(:scope => [],
+ :trusted_keys => [],
+ :keys => [:body]))
+ proc { t.on_scope(params) }.must_raise NoMethodError
+ end
+ end
+ end
+
describe "#key" do
context "scope is empty" do
it "returns nil" do
Please sign in to comment.
Something went wrong with that request. Please try again.