ActiveRecord::Relation with raw SQL argument returns a warning/exception raising.

Fix up with Arel.sql()

Mitsun Chieh

--

Ordering ActiveRecord::Relation with MySQL argument in Rails 6.0.0beta3

In Ruby on Rails > 5.2,

If you still want to use #order or #pluck on our ActiveRecord::Relation using SQL syntax like this[1]. You may need to use Arel.sql() to avoid unsafe_raw SQL warning like following[2]:

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "SOMETHING". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().

And in Ruby on Rails >= 6, it will become to a exception raising:

ActiveRecord::UnknownAttributeReference (Query method called with non-attribute argument(s): "SOMETHING")

This is what you can do:

# Make sure it's a known-safe values.user_ids = [3, 2, 1]# Before 
users = User.where(id: user_ids).order("FIELD(id, 2, 3, 1)")
# With warning.
# After
users = User.where(id: user_ids).order(Arel.sql("FIELD(id, 2, 3, 1)"))
# No warning

NOTICE:

Not every raw SQL argument will bring on this warning:

User.where(id: user_ids).order('users.id desc')
User.where(id: user_ids).order('id desc')
User.where(id: user_ids).order('id')
User.where(id: user_ids).order('users.id')
User.where(id: user_ids).pluck('users.id')
User.where(id: user_ids).pluck('id')
# All of these with correct column format will be allowed

Check all column format white list here[3].

Reference:

[1] Ordering ActiveRecord::Relation with SQL argument

[2] Rails’ PR: Disallow raw SQL in dangerous AR methods #27947

[3] Regexp whitelist for order or pluck

--

--