Rails 5.2以降では、クエリーメソッドのorderやpluckに文字列でSQLを渡すと警告が出ることがあります。
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): 略
Rails 5.2ではメッセージの続きに次の文句がありますが、6.0ではまだ禁止されていません。
Non-attribute arguments will be disallowed in Rails 6.0.
Rails 6.0では次のように出るので、6.1で禁止されるのかな。
Non-attribute arguments will be disallowed in Rails 6.1.
Rails 5.2でorderやpluckの引数をチェックしている箇所は次のコードです。
orderの場合は文字列をカンマで分割して次の正規表現に当てはまるかチェックしています。"name DESC"
や "name DESC NULLS FIRST"
はOKです。
COLUMN_NAME_ORDER_WHITELIST = /
\A
(?:\w+\.)?
\w+
(?:\s+asc|\s+desc)?
(?:\s+nulls\s+(?:first|last))?
\z
/ix
Rails 6.0では、正規表現が大幅に修正され、データベースの種類によって分けられています。PostgreSQLでは次の箇所です。
COLUMN_NAME_WITH_ORDER = /
\A
(
(?:
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
)
(?:\s+ASC|\s+DESC)?
(?:\s+NULLS\s+(?:FIRST|LAST))?
)
(?:\s*,\s*\g<1>)*
\z
/ix
この違いにより、Rails 5.1から5.2に上げたら警告が出るが、6.0に上げると出なくなる、という書き方があります。次のように関数を使った場合です。
User.order("lower(name)") # 5.1 OK, 5.2 Warning, 6.0 OK
この警告が出るのを回避するには、Arel.sql()
で囲みます。
User.order(Arel.sql("lower(name)")) # 5.1 OK, 5.2 OK, 6.0 OK
また、上記5.2と6.0の正規表現を見て気付いた人もいると思いますが、5.2ではカラム名の前後に空白文字を入れるだけで警告が出てしまいます。
User.order("name ") # 5.1 OK, 5.2 Warning, 6.0 OK
5.2のこの仕様は直してほしいなあ。