Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial version to keep your controllers secure by default

  • Loading branch information...
commit 97e8705afcf484c526e17ebe0f4bc65c06a0e225 0 parents
@dcunning dcunning authored
Showing with 849 additions and 0 deletions.
  1. +19 −0 .gitignore
  2. +4 −0 Gemfile
  3. +22 −0 LICENSE
  4. +93 −0 README.md
  5. +7 −0 Rakefile
  6. +8 −0 lib/param_accessible.rb
  7. +41 −0 lib/param_accessible/controller_ext.rb
  8. +19 −0 lib/param_accessible/error.rb
  9. +23 −0 lib/param_accessible/not_acceptable_helper.rb
  10. +93 −0 lib/param_accessible/rule.rb
  11. +58 −0 lib/param_accessible/rules.rb
  12. +3 −0  lib/param_accessible/version.rb
  13. +23 −0 param_accessible.gemspec
  14. +34 −0 spec/app_root/app/controllers/application_controller.rb
  15. +6 −0 spec/app_root/app/controllers/except_controller.rb
  16. +12 −0 spec/app_root/app/controllers/if_false_controller.rb
  17. +12 −0 spec/app_root/app/controllers/if_true_controller.rb
  18. +6 −0 spec/app_root/app/controllers/merge_controller.rb
  19. +6 −0 spec/app_root/app/controllers/not_acceptable_controller.rb
  20. +6 −0 spec/app_root/app/controllers/only_controller.rb
  21. +4 −0 spec/app_root/app/controllers/simple_controller.rb
  22. +12 −0 spec/app_root/app/controllers/unless_false_controller.rb
  23. +12 −0 spec/app_root/app/controllers/unless_true_controller.rb
  24. +12 −0 spec/app_root/config/application.rb
  25. +5 −0 spec/app_root/config/environment.rb
  26. +3 −0  spec/app_root/config/routes.rb
  27. +34 −0 spec/lib/except_spec.rb
  28. +24 −0 spec/lib/if_false_spec.rb
  29. +34 −0 spec/lib/if_true_spec.rb
  30. +20 −0 spec/lib/merge_spec.rb
  31. +30 −0 spec/lib/not_acceptable_helper_spec.rb
  32. +34 −0 spec/lib/only_spec.rb
  33. +57 −0 spec/lib/simple_spec.rb
  34. +34 −0 spec/lib/unless_false_spec.rb
  35. +24 −0 spec/lib/unless_true_spec.rb
  36. +15 −0 spec/spec_helper.rb
19 .gitignore
@@ -0,0 +1,19 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+.rspec
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+spec/app_root/log
+test/tmp
+test/version_tmp
+tmp
4 Gemfile
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in param_accessible.gemspec
+gemspec
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Dan Cunning
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
93 README.md
@@ -0,0 +1,93 @@
+# ParamAccessible
+
+[![Build Status](https://secure.travis-ci.org/topdan/param_accessible.png)](https://secure.travis-ci.org/topdan/param_accessible.png)
+
+Provides a method to help protect your Ruby on Rails controllers from malicious or accidentally destructive user parameters. It is independent, but heavily influenced by param_protected.
+
+Make all your controllers secure by default as well as provide readable messages to users when a security breach was prevented.
+
+For more information on the design considerations please visit: https://www.topdan.com/ruby-on-rails/params-accessible.html
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+ gem 'param_accessible'
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install param_accessible
+
+## Usage
+
+ class ApplicationController < ActionController::Base
+
+ # make all your controllers secure by default
+ before_filter :ensure_params_are_accessible, :only => [:create, :update]
+
+ # expose the common rails parameters
+ param_accessible :controller, :action, :format, :id
+
+ # this error is thrown when the user tries to access an inaccessible param
+ rescue_from ParamAccessible::Error, :with => :handle_param_not_accessible
+
+ protected
+
+ def handle_param_not_accessible e
+ flash[:error] = "You gave me some invalid parameters: #{e.inaccessible_params.join(', )}"
+ redirect_to :back
+ end
+
+ end
+
+ class UserController < ApplicationController
+
+ # these attributes are available for everyone
+ param_accessible :user => {:name, :email, :password, :password_confirmation}
+
+ # these attributes are only available if the controller instance method is_admin? is true
+ param_accessible :user => {:is_admin, :is_locked_out}, :if => :is_admin?
+
+ def update
+ @user = User.find(params[:id])
+
+ # this is now safe!
+ if @user.update_attributes(params[:user])
+ ...
+ else
+ ...
+ end
+ end
+ end
+
+ class DemoController < ApplicationController
+
+ # rescue_from ParamAccessible::Error and respond with a 406 Not Acceptable status
+ # with an HTML, JSON, XML, or JS explanation of which parameters were invalid
+ include ParamAccessible::NotAcceptableHelper
+
+ param_accessible :foo, :if => :is_admin
+ param_accessible :bar, :unless => :logged_in?
+ param_accessible :baz, :only => :show
+ param_accessible :nut, :except => :index
+
+ end
+
+ class InsecureController < ApplicationController
+
+ # skip the filter ApplicationController set up to avoid the accessible parameter checks
+ skip_before_filter :ensure_params_are_accessible
+
+ end
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Added some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
7 Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new('spec')
+
+task :test => :spec
+task :default => :test
8 lib/param_accessible.rb
@@ -0,0 +1,8 @@
+require "param_accessible/version"
+require "param_accessible/error"
+require "param_accessible/rule"
+require "param_accessible/rules"
+require "param_accessible/not_acceptable_helper"
+require "param_accessible/controller_ext"
+
+ActionController::Base.send(:include, ParamAccessible::ControllerExt)
41 lib/param_accessible/controller_ext.rb
@@ -0,0 +1,41 @@
+module ParamAccessible
+
+ module ControllerExt
+ extend ActiveSupport::Concern
+
+ protected
+
+ def ensure_params_are_accessible
+ inaccessible_params = param_accessible_rules.detect_inaccessible_params self
+
+ unless inaccessible_params.nil? || inaccessible_params.blank?
+ raise ParamAccessible::Error.new(inaccessible_params)
+ end
+ end
+
+ def param_accessible_rules
+ self.class.param_accessible_rules
+ end
+
+ module ClassMethods
+
+ def param_accessible *args
+ param_accessible_rules.push *args
+ end
+
+ def param_accessible_rules
+ return @param_accessible_rules if defined? @param_accessible_rules
+
+ # inheritance
+ if superclass.respond_to?(:param_accessible_rules)
+ @param_accessible_rules = Rules.new superclass.param_accessible_rules
+ else
+ @param_accessible_rules = Rules.new
+ end
+ end
+
+ end
+
+ end
+
+end
19 lib/param_accessible/error.rb
@@ -0,0 +1,19 @@
+module ParamAccessible
+
+ class Error < Exception
+
+ attr_reader :inaccessible_params
+
+ def initialize inaccessible_params
+ if inaccessible_params.length == 1
+ super "#{inaccessible_params.join(', ')} is an invalid parameter"
+ else
+ super "#{inaccessible_params.join(', ')} are invalid parameters"
+ end
+
+ @inaccessible_params = inaccessible_params
+ end
+
+ end
+
+end
23 lib/param_accessible/not_acceptable_helper.rb
@@ -0,0 +1,23 @@
+module ParamAccessible
+
+ module NotAcceptableHelper
+ extend ActiveSupport::Concern
+
+ included do
+ rescue_from ParamAccessible::Error, :with => :handle_param_not_accessible
+ end
+
+ protected
+
+ def handle_param_not_accessible error
+ respond_to do |format|
+ format.html { render :status => 406, :text => error.message }
+ format.json { render :status => 406, :json => {:error => {:message => "You supplied invalid parameters: #{error.inaccessible_params.join(', ')}"}} }
+ format.xml { render :status => 406, :xml => {:message => "You supplied invalid parameters: #{error.inaccessible_params.join(', ')}"}.to_xml('error') }
+ format.js { render :status => 406, :text => %(// invalid parameters: #{error.inaccessible_params.join(', ')}\n) }
+ end
+ end
+
+ end
+
+end
93 lib/param_accessible/rule.rb
@@ -0,0 +1,93 @@
+module ParamAccessible
+
+ class Rule
+
+ attr_reader :attributes
+ attr_reader :if_option, :unless_option
+ attr_reader :only_options, :except_options
+
+ def initialize *args
+ if args.length > 1 && args.last.is_a?(Hash)
+ options = args.last
+ attributes = args[0..-2]
+
+ options.assert_valid_keys :if, :unless, :only, :except
+ # options = normalize_options options
+ else
+ options = {}
+ attributes = args
+ end
+
+ @if_option = options[:if]
+ @unless_option = options[:unless]
+
+ @only_options = clean_action_option options[:only]
+ @except_options = clean_action_option options[:except]
+
+ @attributes = normalize_params attributes
+ end
+
+ def clean_action_option value
+ return if value == nil
+ value = [value] unless value.is_a?(Array)
+ value.collect {|v| v.to_s }
+ end
+
+ def accessible_params_for controller, dest
+ return if @if_option != nil && !controller.send(@if_option)
+ return if @unless_option != nil && controller.send(@unless_option)
+
+ return if @only_options != nil && !@only_options.include?(controller.action_name)
+ return if @except_options != nil && @except_options.include?(controller.action_name)
+
+ accessible_hash_for controller, @attributes, dest
+ end
+
+ protected
+
+ def accessible_hash_for controller, attributes, dest
+ attributes.each do |key, value|
+ if value.is_a?(Hash)
+ attrs = dest[key]
+ if attrs.nil?
+ attrs = {}
+ dest[key] = attrs
+ end
+
+ accessible_hash_for controller, value, attrs
+ else
+ dest[key] = value
+ end
+ end
+ end
+
+ # When specifying params to protect, we allow a combination of arrays and hashes much like how
+ # ActiveRecord::Base#find's :include options works. This method normalizes that into just nested hashes,
+ # stringifying the keys and setting all values to nil. This format is easier/faster to work with when
+ # filtering the controller params.
+ # Example...
+ # [:a, {:b => [:c, :d]}]
+ # to
+ # {"a"=>nil, "b"=>{"c"=>nil, "d"=>nil}}
+ def normalize_params(params, params_out = {})
+ if params.instance_of?(Array)
+ params.each{ |param| normalize_params(param, params_out) }
+ elsif params.instance_of?(Hash)
+ params.each do |k, v|
+ k = normalize_key(k)
+ params_out[k] = {}
+ normalize_params(v, params_out[k])
+ end
+ else
+ params_out[normalize_key(params)] = nil
+ end
+ params_out
+ end
+
+ def normalize_key(k)
+ k.to_s
+ end
+
+ end
+
+end
58 lib/param_accessible/rules.rb
@@ -0,0 +1,58 @@
+module ParamAccessible
+
+ class Rules < Array
+
+ def initialize parent = nil
+ content = (parent.to_a if parent) || []
+ super content
+ end
+
+ def detect_inaccessible_params controller
+ accessible_params = {}
+
+ each do |rule|
+ rule.accessible_params_for controller, accessible_params
+ end
+
+ detect_inaccessible_hash controller.params, accessible_params, []
+ end
+
+ def push *args
+ super Rule.new(*args)
+ end
+
+ protected
+
+ def detect_inaccessible_hash hash, accessible, errors, prefix = nil
+ hash.each do |key, value|
+ if !accessible.has_key?(key)
+ errors.push prefix_for(prefix, key)
+
+ elsif value.is_a?(Hash)
+ nested = accessible[key] || {}
+ detect_inaccessible_hash value, nested, errors, prefix_for(prefix, key)
+
+ elsif value.is_a?(Array)
+ nested = accessible[key] || {}
+ value.each do |v|
+ if v.is_a?(Hash)
+ detect_inaccessible_hash v, nested, errors, prefix_for(prefix, key)
+ end
+ end
+ end
+ end
+
+ errors
+ end
+
+ def prefix_for prefix, key
+ if prefix
+ "#{prefix}[#{key}]"
+ else
+ key
+ end
+ end
+
+ end
+
+end
3  lib/param_accessible/version.rb
@@ -0,0 +1,3 @@
+module ParamAccessible
+ VERSION = "0.0.1"
+end
23 param_accessible.gemspec
@@ -0,0 +1,23 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/param_accessible/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Dan Cunning"]
+ gem.email = ["dan@topdan.com"]
+ gem.description = %q{Help secure your controllers from malicious parameters}
+ gem.summary = %q{Help secure your controllers from malicious parameters}
+ gem.homepage = ""
+
+ gem.files = `git ls-files`.split($\)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.name = "param_accessible"
+ gem.require_paths = ["lib"]
+ gem.version = ParamAccessible::VERSION
+
+ gem.add_dependency 'activesupport', '>= 3.0.0'
+ gem.add_dependency 'actionpack', '>= 3.0.0'
+ gem.add_development_dependency 'rails', '>= 3.0.0'
+ gem.add_development_dependency 'rspec-rails'
+ gem.add_development_dependency "simplecov"
+end
34 spec/app_root/app/controllers/application_controller.rb
@@ -0,0 +1,34 @@
+class ApplicationController < ActionController::Base
+ before_filter :ensure_params_are_accessible, :only => [:create, :update]
+ before_filter :render_nothing
+
+ param_accessible :action, :controller, :format
+
+ def index
+ end
+
+ def show
+ end
+
+ def new
+ end
+
+ def create
+ end
+
+ def edit
+ end
+
+ def update
+ end
+
+ def destroy
+ end
+
+private
+
+ def render_nothing
+ render :nothing => true
+ end
+
+end
6 spec/app_root/app/controllers/except_controller.rb
@@ -0,0 +1,6 @@
+class ExceptController < ApplicationController
+
+ param_accessible :foo, :except => :create
+ param_accessible({:bar => [:baz]}, :except => :update)
+
+end
12 spec/app_root/app/controllers/if_false_controller.rb
@@ -0,0 +1,12 @@
+class IfFalseController < ApplicationController
+
+ param_accessible :foo, :if => :admin?
+ param_accessible({:bar => [:baz]}, :if => :admin?)
+
+ protected
+
+ def admin?
+ false
+ end
+
+end
12 spec/app_root/app/controllers/if_true_controller.rb
@@ -0,0 +1,12 @@
+class IfTrueController < ApplicationController
+
+ param_accessible :foo, :if => :admin?
+ param_accessible({:bar => [:baz]}, :if => :admin?)
+
+ protected
+
+ def admin?
+ true
+ end
+
+end
6 spec/app_root/app/controllers/merge_controller.rb
@@ -0,0 +1,6 @@
+class MergeController < ApplicationController
+ param_accessible :a, :only => :create
+ param_accessible :b
+ param_accessible({ :h => :c}, :except => :update)
+ param_accessible :h => :b
+end
6 spec/app_root/app/controllers/not_acceptable_controller.rb
@@ -0,0 +1,6 @@
+class NotAcceptableController < ApplicationController
+ include ParamAccessible::NotAcceptableHelper
+
+ param_accessible :foo
+
+end
6 spec/app_root/app/controllers/only_controller.rb
@@ -0,0 +1,6 @@
+class OnlyController < ApplicationController
+
+ param_accessible :foo, :only => :create
+ param_accessible({:bar => [:baz]}, :only => :update)
+
+end
4 spec/app_root/app/controllers/simple_controller.rb
@@ -0,0 +1,4 @@
+class SimpleController < ApplicationController
+ # TODO move action and controller up a level
+ param_accessible [:foo, {:bar => [:baz, :nuts]}]
+end
12 spec/app_root/app/controllers/unless_false_controller.rb
@@ -0,0 +1,12 @@
+class UnlessFalseController < ApplicationController
+
+ param_accessible :foo, :unless => :admin?
+ param_accessible({:bar => [:baz]}, :unless => :admin?)
+
+ protected
+
+ def admin?
+ false
+ end
+
+end
12 spec/app_root/app/controllers/unless_true_controller.rb
@@ -0,0 +1,12 @@
+class UnlessTrueController < ApplicationController
+
+ param_accessible :foo, :unless => :admin?
+ param_accessible({:bar => [:baz]}, :unless => :admin?)
+
+ protected
+
+ def admin?
+ true
+ end
+
+end
12 spec/app_root/config/application.rb
@@ -0,0 +1,12 @@
+require "action_controller/railtie"
+
+module TestApp
+ class Application < Rails::Application
+ config.root = File.join(File.expand_path('.'), 'spec', 'app_root')
+ config.cache_classes = false
+ config.whiny_nils = true
+ config.secret_token = 'd229e4d22437432705ab3985d4d246'
+ config.session_store :cookie_store, :key => 'rails_session'
+ config.active_support.deprecation = :stderr
+ end
+end
5 spec/app_root/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the rails application
+require File.expand_path('../application', __FILE__)
+
+# Initialize the rails application
+TestApp::Application.initialize!
3  spec/app_root/config/routes.rb
@@ -0,0 +1,3 @@
+TestApp::Application.routes.draw do
+ match ':controller(/:action(/:id(.:format)))'
+end
34 spec/lib/except_spec.rb
@@ -0,0 +1,34 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe ExceptController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should limit those attribute to ONLY those actions" do
+ post :update, :foo => "hi"
+ response.code.should == "200"
+ end
+
+ it "should disallow unknown attributes from those actions" do
+ begin
+ post :update, :bar => "hi"
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar)
+ end
+ end
+
+ it "should obey nested attributes" do
+ post :create, :bar => {:baz => 'hi'}
+ response.code.should == "200"
+ end
+
+ it "should catch invalid nested attributes for those actions" do
+ begin
+ post :create, :bar => {:foo => 'hi'}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar[foo])
+ end
+ end
+
+end
24 spec/lib/if_false_spec.rb
@@ -0,0 +1,24 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe IfFalseController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should not allow the attribute" do
+ begin
+ post :create, :foo => "hi"
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(foo)
+ end
+ end
+
+ it "should not allow the nested attribute" do
+ begin
+ post :create, :bar => {:baz => "hi"}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar)
+ end
+ end
+
+end
34 spec/lib/if_true_spec.rb
@@ -0,0 +1,34 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe IfTrueController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should allow valid attributes" do
+ post :create, :foo => "hi"
+ response.code.should == "200"
+ end
+
+ it "should disallow invalid attributes" do
+ begin
+ post :create, :nuts => "hi"
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(nuts)
+ end
+ end
+
+ it "should allow valid nested attributes" do
+ post :update, :bar => {:baz => 'hi'}
+ response.code.should == "200"
+ end
+
+ it "should disallow invalid nested attributes" do
+ begin
+ post :update, :bar => {:foo => 'hi'}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar[foo])
+ end
+ end
+
+end
20 spec/lib/merge_spec.rb
@@ -0,0 +1,20 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe MergeController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should allow a combination of all rules following the options" do
+ post :create, :a => 'hi', :b => 'ho', :h => {:b => 'hey', :c => 'fo'}
+ response.code.should == "200"
+ end
+
+ it "should not allow combinations outside of the options" do
+ begin
+ post :update, :a => 'hi', :b => 'ho', :h => {:b => 'hey', :c => 'fo'}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(a h[c])
+ end
+ end
+
+end
30 spec/lib/not_acceptable_helper_spec.rb
@@ -0,0 +1,30 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe NotAcceptableController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should rescue_from HTML and render 406" do
+ post :create, :bar => 'hi'
+ response.code.should == "406"
+ response.body.should include "bar is an invalid parameter"
+ end
+
+ it "should rescue_from json and render 406" do
+ post :create, :bar => 'hi', :format => "json"
+ response.code.should == "406"
+ response.body.should == {:error => {:message => "You supplied invalid parameters: bar"}}.to_json
+ end
+
+ it "should rescue_from xml and render 406" do
+ post :create, :bar => 'hi', :format => "json"
+ response.code.should == "406"
+ response.body.should == {:error => {:message => "You supplied invalid parameters: bar"}}.to_json
+ end
+
+ it "should rescue_from js and render 406" do
+ post :create, :bar => 'hi', :format => "js"
+ response.code.should == "406"
+ response.body.should == "// invalid parameters: bar\n"
+ end
+
+end
34 spec/lib/only_spec.rb
@@ -0,0 +1,34 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe OnlyController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should limit those attribute to ONLY those actions" do
+ post :create, :foo => "hi"
+ response.code.should == "200"
+ end
+
+ it "should disallow unknown attributes from those actions" do
+ begin
+ post :create, :bar => "hi"
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar)
+ end
+ end
+
+ it "should obey nested attributes" do
+ post :update, :bar => {:baz => 'hi'}
+ response.code.should == "200"
+ end
+
+ it "should catch invalid nested attributes for those actions" do
+ begin
+ post :update, :bar => {:foo => 'hi'}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar[foo])
+ end
+ end
+
+end
57 spec/lib/simple_spec.rb
@@ -0,0 +1,57 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe SimpleController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should not complain if the attributes are missing" do
+ post :create
+ response.code.should == "200"
+ end
+
+ it "should not complain if a subset of those attributes are given" do
+ post :create, :foo => 'hi'
+ response.code.should == "200"
+ end
+
+ it "should not complain if exactly those attributes are given" do
+ post :create, :foo => 'hi', :bar => {:baz => 'hey', :nuts => 'ho'}
+ response.code.should == "200"
+ end
+
+ it "should not complain on actions outside of the before_filter" do
+ get :show, :unknown => 'hi'
+ response.code.should == '200'
+ end
+
+ it "should complain an unknown attribute is given" do
+ begin
+ post :create, :unknown => 'hi'
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(unknown)
+ end
+ end
+
+ it "should complain an unknown nested attribute is given" do
+ begin
+ post :create, :bar => {:unknown => 'hi'}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar[unknown])
+ end
+ end
+
+ it "should handle nested arrays" do
+ post :create, :bar => [:baz => 'hi']
+ response.code.should == '200'
+ end
+
+ it "should be fine when the ONLY value is a value but not an options hash" do
+ SimpleController.param_accessible :bar => []
+ end
+
+ it "should raise an error when the last value is a hash, but not an options hash" do
+ lambda { SimpleController.param_accessible :foo, :bar => [] }.should raise_error(ArgumentError)
+ end
+
+end
34 spec/lib/unless_false_spec.rb
@@ -0,0 +1,34 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe UnlessFalseController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should allow valid attributes" do
+ post :create, :foo => "hi"
+ response.code.should == "200"
+ end
+
+ it "should disallow invalid attributes" do
+ begin
+ post :create, :nuts => "hi"
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(nuts)
+ end
+ end
+
+ it "should allow valid nested attributes" do
+ post :update, :bar => {:baz => 'hi'}
+ response.code.should == "200"
+ end
+
+ it "should disallow invalid nested attributes" do
+ begin
+ post :update, :bar => {:foo => 'hi'}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar[foo])
+ end
+ end
+
+end
24 spec/lib/unless_true_spec.rb
@@ -0,0 +1,24 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe UnlessTrueController do
+ include RSpec::Rails::ControllerExampleGroup
+
+ it "should not allow the attribute" do
+ begin
+ post :create, :foo => "hi"
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(foo)
+ end
+ end
+
+ it "should not allow the nested attribute" do
+ begin
+ post :create, :bar => {:baz => "hi"}
+ raise "should fail"
+ rescue ParamAccessible::Error => e
+ e.inaccessible_params.should == %w(bar)
+ end
+ end
+
+end
15 spec/spec_helper.rb
@@ -0,0 +1,15 @@
+require 'rubygems'
+require 'bundler/setup'
+
+require "#{File.dirname(__FILE__)}/app_root/config/environment"
+
+require 'simplecov'
+SimpleCov.start do
+ add_filter do |src|
+ src.filename =~ /\/spec\//
+ end
+end
+
+require 'rspec'
+require 'rspec/rails'
+require 'param_accessible'
Please sign in to comment.
Something went wrong with that request. Please try again.