diff options
9 files changed, 157 insertions, 25 deletions
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index da380dfbd8..05c504f608 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -20,6 +20,20 @@ module ActionController end end + # Raised when a supplied parameter is not permitted. + # + # params = ActionController::Parameters.new(a: "123", b: "456") + # params.permit(:c) + # # => ActionController::UnpermittedParameters: found unpermitted keys: a, b + class UnpermittedParameters < IndexError + attr_reader :params + + def initialize(params) + @params = params + super("found unpermitted keys: #{params.join(", ")}") + end + end + # == Action Controller \Parameters # # Allows to choose which attributes should be whitelisted for mass updating @@ -44,10 +58,15 @@ module ActionController # Person.first.update!(permitted) # # => #<Person id: 1, name: "Francesco", age: 22, role: "user"> # - # It provides a +permit_all_parameters+ option that controls the top-level - # behaviour of new instances. If it's +true+, all the parameters will be + # It provides two options that controls the top-level behavior of new instances: + # + # * +permit_all_parameters+ - If it's +true+, all the parameters will be # permitted by default. The default value for +permit_all_parameters+ # option is +false+. + # * +raise_on_unpermitted_parameters+ - If it's +true+, it will raise an exception + # if parameters that are not explicitly permitted are found. The default value for + # +raise_on_unpermitted_parameters+ # option is +true+ in test and development + # environments, +false+ otherwise. # # params = ActionController::Parameters.new # params.permitted? # => false @@ -57,6 +76,16 @@ module ActionController # params = ActionController::Parameters.new # params.permitted? # => true # + # params = ActionController::Parameters.new(a: "123", b: "456") + # params.permit(:c) + # # => {} + # + # ActionController::Parameters.raise_on_unpermitted_parameters = true + # + # params = ActionController::Parameters.new(a: "123", b: "456") + # params.permit(:c) + # # => ActionController::UnpermittedParameters: found unpermitted keys: a, b + # # <tt>ActionController::Parameters</tt> is inherited from # <tt>ActiveSupport::HashWithIndifferentAccess</tt>, this means # that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>. @@ -66,6 +95,7 @@ module ActionController # params["key"] # => "value" class Parameters < ActiveSupport::HashWithIndifferentAccess cattr_accessor :permit_all_parameters, instance_accessor: false + cattr_accessor :raise_on_unpermitted_parameters, instance_accessor: false # Returns a new instance of <tt>ActionController::Parameters</tt>. # Also, sets the +permitted+ attribute to the default value of @@ -223,6 +253,13 @@ module ActionController end end + if Parameters.raise_on_unpermitted_parameters + unpermitted_keys = self.keys - params.keys + if unpermitted_keys.any? + raise ActionController::UnpermittedParameters.new(unpermitted_keys) + end + end + params.permit! end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 3e44155f73..731d66b0cf 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -20,22 +20,25 @@ module ActionController end initializer "action_controller.parameters_config" do |app| - ActionController::Parameters.permit_all_parameters = app.config.action_controller.delete(:permit_all_parameters) { false } + options = app.config.action_controller + + ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false } + ActionController::Parameters.raise_on_unpermitted_parameters = options.delete(:raise_on_unpermitted_parameters) { Rails.env.test? || Rails.env.development? } end initializer "action_controller.set_configs" do |app| paths = app.config.paths options = app.config.action_controller - options.logger ||= Rails.logger - options.cache_store ||= Rails.cache + options.logger ||= Rails.logger + options.cache_store ||= Rails.cache - options.javascripts_dir ||= paths["public/javascripts"].first - options.stylesheets_dir ||= paths["public/stylesheets"].first + options.javascripts_dir ||= paths["public/javascripts"].first + options.stylesheets_dir ||= paths["public/stylesheets"].first # Ensure readers methods get compiled - options.asset_host ||= app.config.asset_host - options.relative_url_root ||= app.config.relative_url_root + options.asset_host ||= app.config.asset_host + options.relative_url_root ||= app.config.relative_url_root ActiveSupport.on_load(:action_controller) do include app.routes.mounted_helpers diff --git a/actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb b/actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb new file mode 100644 index 0000000000..747b8123ea --- /dev/null +++ b/actionpack/test/controller/parameters/raise_on_unpermitted_parameters_test.rb @@ -0,0 +1,33 @@ +require 'abstract_unit' +require 'action_controller/metal/strong_parameters' + +class RaiseOnUnpermittedParametersTest < ActiveSupport::TestCase + def setup + ActionController::Parameters.raise_on_unpermitted_parameters = true + end + + def teardown + ActionController::Parameters.raise_on_unpermitted_parameters = false + end + + test "raises on unexpected params" do + params = ActionController::Parameters.new({ + book: { pages: 65 }, + fishing: "Turnips" + }) + + assert_raises(ActionController::UnpermittedParameters) do + params.permit(book: [:pages]) + end + end + + test "raises on unexpected nested params" do + params = ActionController::Parameters.new({ + book: { pages: 65, title: "Green Cats and where to find then." } + }) + + assert_raises(ActionController::UnpermittedParameters) do + params.permit(book: [:pages]) + end + end +end diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb index 06e0983780..b628b0cd90 100644 --- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb +++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb @@ -100,6 +100,7 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase assert_equal :inet, @first_network_address.column_for_attribute(:inet_address).type assert_equal :macaddr, @first_network_address.column_for_attribute(:mac_address).type end + def test_data_type_of_bit_string_types assert_equal :string, @first_bit_string.column_for_attribute(:bit_string).type assert_equal :string, @first_bit_string.column_for_attribute(:bit_string_varying).type diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb index 20228d1fc4..5d12ca75ca 100644 --- a/activerecord/test/cases/adapters/postgresql/ltree_test.rb +++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb @@ -1,5 +1,4 @@ # encoding: utf-8 - require "cases/helper" require 'active_record/base' require 'active_record/connection_adapters/postgresql_adapter' @@ -11,16 +10,13 @@ class PostgresqlLtreeTest < ActiveRecord::TestCase def setup @connection = ActiveRecord::Base.connection - begin - @connection.transaction do - @connection.create_table('ltrees') do |t| - t.ltree 'path' - end + @connection.transaction do + @connection.create_table('ltrees') do |t| + t.ltree 'path' end - rescue ActiveRecord::StatementInvalid - return skip "do not test on PG without ltree" end - @column = Ltree.columns.find { |c| c.name == 'path' } + rescue ActiveRecord::StatementInvalid + skip "do not test on PG without ltree" end def teardown @@ -28,17 +24,18 @@ class PostgresqlLtreeTest < ActiveRecord::TestCase end def test_column - assert_equal :ltree, @column.type + column = Ltree.columns_hash['path'] + assert_equal :ltree, column.type end def test_write - x = Ltree.new(:path => '1.2.3.4') - assert x.save! + ltree = Ltree.new(path: '1.2.3.4') + assert ltree.save! end def test_select @connection.execute "insert into ltrees (path) VALUES ('1.2.3')" - x = Ltree.first - assert_equal('1.2.3', x.path) + ltree = Ltree.first + assert_equal '1.2.3', ltree.path end end diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb index 78580b220c..4497ef61df 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console.rb @@ -37,7 +37,7 @@ module Rails private def available_environments - Dir[Rails.root.join('config', 'environments', '*.rb')].map { |fname| File.basename(fname, '.*') } + Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') } end end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index 2d1e2d6a45..5914c9e4ae 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -147,7 +147,7 @@ module Rails end def available_environments - Dir[Rails.root.join('config', 'environments', '*.rb')].map { |fname| File.basename(fname, '.*') } + Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') } end def find_cmd_and_exec(commands, *args) diff --git a/railties/lib/rails/generators/rails/migration/USAGE b/railties/lib/rails/generators/rails/migration/USAGE index f340ed97f2..baf3d9894f 100644 --- a/railties/lib/rails/generators/rails/migration/USAGE +++ b/railties/lib/rails/generators/rails/migration/USAGE @@ -20,3 +20,16 @@ Example: add_column :posts, :title, :string add_column :posts, :body, :text add_column :posts, :published, :boolean + +Migration names containing JoinTable will generate join tables for use with +has_and_belongs_to_many associations. + +Example: + `rails g migration CreateMediaJoinTable artists musics:uniq` + + will create the migration + + create_join_table :artists, :musics do |t| + # t.index [:artist_id, :music_id] + t.index [:music_id, :artist_id], unique: true + end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 920798c930..e41b21e21a 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -567,6 +567,54 @@ module ApplicationTests assert_equal 'permitted', last_response.body end + test "config.action_controller.raise_on_unpermitted_parameters = true" do + app_file 'app/controllers/posts_controller.rb', <<-RUBY + class PostsController < ActionController::Base + def create + render text: params.require(:post).permit(:name) + end + end + RUBY + + add_to_config <<-RUBY + routes.prepend do + resources :posts + end + config.action_controller.raise_on_unpermitted_parameters = true + RUBY + + require "#{app_path}/config/environment" + + assert_equal true, ActionController::Parameters.raise_on_unpermitted_parameters + + post "/posts", {post: {"title" =>"zomg"}} + assert_match "We're sorry, but something went wrong", last_response.body + end + + test "config.action_controller.raise_on_unpermitted_parameters is true by default on development" do + ENV["RAILS_ENV"] = "development" + + require "#{app_path}/config/environment" + + assert_equal true, ActionController::Parameters.raise_on_unpermitted_parameters + end + + test "config.action_controller.raise_on_unpermitted_parameters is true by defaul on test" do + ENV["RAILS_ENV"] = "test" + + require "#{app_path}/config/environment" + + assert_equal true, ActionController::Parameters.raise_on_unpermitted_parameters + end + + test "config.action_controller.raise_on_unpermitted_parameters is false by default on production" do + ENV["RAILS_ENV"] = "production" + + require "#{app_path}/config/environment" + + assert_equal false, ActionController::Parameters.raise_on_unpermitted_parameters + end + test "config.action_dispatch.ignore_accept_header" do make_basic_app do |app| app.config.action_dispatch.ignore_accept_header = true |