0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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モデル

>```ruby: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.セレクトボックスフォームのコード。

>```ruby: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アクション。

>```ruby: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


###エラー内容

>```ruby
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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?