0
0

More than 3 years have passed since last update.

【Railsエラー】DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s)...

Last updated at Posted at 2020-06-07

始めに

投稿のいいね数の順番によってソートする機能実装中に遭遇したエラーに関するメモです。

前提

Ruby 2.6系
Rails 5.2系
Slim導入済
devise導入済

実装されている内容

1.User、Post、Favoriteモデルが存在する。
2.favoritesテーブルを中間テーブルとして、usersテーブルとpostsテーブルが関連付けされている。

Favoriteモデル

app/models/favorite.rb
class Favorite < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

Postモデル

app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :favorites
end

Userモデル

app/models/user.rb
class User < ApplicationRecord
  has_many :favorites
  has_many :favorite_posts, through: :favorites, source: :post
  has_many :posts
end
3.セレクトボックスフォームのコード。
app/views/index.html.slim
= form_with url: search_path, method: :get, local: true do |form|
  = form.select :keyword, [ 
                            ['いいねが多い順', 'likes'],
                            ['いいねが少ない順', 'dislikes'],
                          ]
  = form.submit
4.ルーティング。
config/routes.rb
Rails.application.routes.draw do
  #検索結果をpostsコントローラのsearchアクションへ送信
  get 'search' => 'posts#search'
  resources :posts 
end
5.条件に一致したPostを取得するpostsコントローラのsearchアクション。
app/controllers/posts_controller.rb
def search
    @selection = params[:keyword]
    if @selection == 'likes'
      @posts = Post.find(Favorite.group(:post_id).order('count(user_id) desc').pluck(:post_id))
    elsif @selection == 'dislikes'
      @posts = Post.find(Favorite.group(:post_id).order('count(user_id) asc').pluck(:post_id))
    end
end

エラー地点

postsコントローラのsearchアクション内。
app/controllers/posts_controller.rb
def search
    @selection = params[:keyword]
    if @selection == 'likes'
      @posts = Post.find(Favorite.group(:post_id).order('count(user_id) desc').pluck(:post_id))
    elsif @selection == 'dislikes'
      @posts = Post.find(Favorite.group(:post_id).order('count(user_id) asc').pluck(:post_id))
    end
end

エラー内容

DEPRECATION WARNING: 
Dangerous query method 
(method whose arguments are used as raw SQL) 
called with non-attribute argument(s): "count(user_id) desc". 
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().

読んでみると、"count(user_id) desc"に問題があって、Known-safe values can be passed by wrapping them in Arel.sql().を適用させれば解決できるとのこと。

なので、該当箇所を以下のように記述します。

app/controllers/posts_controller.rb
def search
    @selection = params[:keyword]
    if @selection == 'likes'
      @posts = ... ...order(Arel.sql('count(user_id) desc'))... ...
    elsif @selection == 'dislikes'
      @posts = ... ...order(Arel.sql('count(user_id) asc'))... ...
    end
end

先ほどとの違いは、order内のcountメソッドを使った文字列をArel.sql()で囲んでるところ。

こうしなければならない理由は、Rails6.0以降SQLインジェクションの脆弱性ゆえに、第三者から勝手にパラメータを潜り込ませるのを防ぐためとかなんとか。

しかしこれで解決はできました、良かったです。

参考

Rails 6 以降は order/pluck の引数に SQL 文字列を渡すことはできない (容易に対策可能)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0