diff options
author | Xavier Noria <fxn@hashref.com> | 2018-03-06 02:27:16 +0100 |
---|---|---|
committer | Xavier Noria <fxn@hashref.com> | 2018-03-06 02:27:16 +0100 |
commit | 6c82b6c99d86f37e61f935fb342cccd725d6c7d4 (patch) | |
tree | 865d496c43f38103dfdb31af7ef09181a88d1916 | |
parent | 9cc88043e70f927a3c8b151c862f6b3cb8b8a6f7 (diff) | |
download | rails-6c82b6c99d86f37e61f935fb342cccd725d6c7d4.tar.gz rails-6c82b6c99d86f37e61f935fb342cccd725d6c7d4.tar.bz2 rails-6c82b6c99d86f37e61f935fb342cccd725d6c7d4.zip |
whitelist NULLS { FIRST | LAST } in order clauses
-rw-r--r-- | activerecord/lib/active_record/attribute_methods.rb | 9 | ||||
-rw-r--r-- | activerecord/test/cases/unsafe_raw_sql_test.rb | 20 |
2 files changed, 28 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 0ca0e5dcdb..122140eb55 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -177,7 +177,14 @@ module ActiveRecord # "#{table_name}.#{column_name} #{direction}" # "#{column_name}" # "#{column_name} #{direction}" - COLUMN_NAME_ORDER_WHITELIST = /\A(?:\w+\.)?\w+(?:\s+asc|\s+desc)?\z/i + COLUMN_NAME_ORDER_WHITELIST = / + \A + (?:\w+\.)? + \w+ + (?:\s+asc|\s+desc)? + (?:\s+nulls\s+(?:first|last))? + \z + /ix def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc: unexpected = args.reject do |arg| diff --git a/activerecord/test/cases/unsafe_raw_sql_test.rb b/activerecord/test/cases/unsafe_raw_sql_test.rb index 72d4997d0b..d5d8f2a09a 100644 --- a/activerecord/test/cases/unsafe_raw_sql_test.rb +++ b/activerecord/test/cases/unsafe_raw_sql_test.rb @@ -107,6 +107,26 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase assert_equal ids_expected, ids_disabled end + test "order: allows NULLS FIRST and NULLS LAST too" do + raise "precondition failed" if Post.count < 2 + + # Ensure there are NULL and non-NULL post types. + Post.first.update_column(:type, nil) + Post.last.update_column(:type, "Programming") + + ["asc", "desc", ""].each do |direction| + %w(first last).each do |position| + ids_expected = Post.order(Arel.sql("type #{direction} nulls #{position}")).pluck(:id) + + ids_depr = with_unsafe_raw_sql_deprecated { Post.order("type #{direction} nulls #{position}").pluck(:id) } + ids_disabled = with_unsafe_raw_sql_disabled { Post.order("type #{direction} nulls #{position}").pluck(:id) } + + assert_equal ids_expected, ids_depr + assert_equal ids_expected, ids_disabled + end + end + end if current_adapter?(:PostgreSQLAdapter) + test "order: disallows invalid column name" do with_unsafe_raw_sql_disabled do assert_raises(ActiveRecord::UnknownAttributeReference) do |