Help us understand the problem. What is going on with this article?

Rails6 のちょい足しな新機能を試す105(カラム名編)

More than 1 year has passed since last update.

はじめに

Rails 6 に追加された新機能を試す第105段。 今回は、 カラム名編です。
Rails 6 では、 pluckorder で指定するカラムの書き方が "table"."column" でも Arel.sql() で囲いなさいという警告が出なくなりました。
Arel.sql() で囲っても囲わなくても結果としては変わらないことが理由のようです。
この変更に伴い、 Rails 5.2.3 で出ていたRails 6.0 では禁止となると DEPRECATION WARNING が出ていたところが、Rails 6.0 で禁止にならず、Rails 6.1 に持ち越されました。

(注意: Rails 6.0.1 がリリースされましたが、動作確認時点での最新版は、Rails 6.0.0 でした。 Rails 6.0.1 では未確認です :bow:)

Ruby 2.6.5, Rails 6.0.0, Rails 5.2.3 で確認しました。
また、データベースは、 PostgreSQL 12.0 を使っています。

$ rails --version
Rails 6.0.0

今回は、User モデルを作って、 rails console で確認します。

Rails プロジェクトを作る

$ rails new rails_sandbox
cd rails_sandbox

User のモデルを作成する

$ bin/rails g model User name

データベースのマイグレーションを実行する

$ bin/rails db:create db:migrate

rails console で確認します。

User.order の引数を変更して確認します。

name を指定する

name を指定したときは、警告は出ません。

irb(main):001:0> User.order("name")
  User Load (0.9ms)  SELECT "users".* FROM "users" ORDER BY name LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

users.name を指定する

users.name を指定したときは、警告は出ません。

irb(main):002:0> User.order("users.name")
  User Load (0.9ms)  SELECT "users".* FROM "users" ORDER BY users.name LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

"users"."name" を指定する

"users"."name" を指定したときも、警告は出ません。

irb(main):003:0> User.order('"users"."name"')
  User Load (0.9ms)  SELECT "users".* FROM "users" ORDER BY "users"."name" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

name /* comment */ を指定する

name /* comment */ を指定したときは、 DEPRECATION WARNING が出ます。

irb(main):006:0> User.order("name /* comment */")
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "name /* comment */". Non-attribute arguments will be disallowed in Rails 6.1. 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(). (called from irb_binding at (irb):6)
  User Load (0.8ms)  SELECT "users".* FROM "users" ORDER BY name /* comment */ LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

Rails 5 では

Rails 5.2.3 では、 name /* comment */ を指定したときの他、 "users"."name" のときも DEPRECATION WARNING が表示されます。

irb(main):003:0> User.order('"users"."name"')
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "\"users\".\"name\"". 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(). (called from irb_binding at (irb):3)
  User Load (0.8ms)  SELECT  "users".* FROM "users" ORDER BY "users"."name" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

Arel.sql() で囲ってみても結果的に実行されるSQL は、警告が出ていたときと何ら変りありません。

irb(main):005:0> User.order(Arel.sql('"users"."name"'))
  User Load (0.9ms)  SELECT  "users".* FROM "users" ORDER BY "users"."name" LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try105_disallow_row_sql

参考情報

suketa
Rails初心者なRubyコミッター
ruby-dev
Ruby開発はRuby on Railsをコア技術とし、Web系から基幹系まで多様な開発に携わっています。
https://www.ruby-dev.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away