踩坑 query method。

问题描述

现有model issue,需要对issues进行排序,根据指定的ID集合来决定记录的位置,比如id包含在(4, 6, 9)中的纪录就排在前面,剩下的排在后面。

使用scope进行处理:

class Issue < ApplicationRecord
.........
IDLIST = [4, 6, 9]
scope :order_by_custom_id, -> {
order_by = ['CASE']
order_by << "WHEN id in (#{IDLIST.join(', ')}) THEN 0"
order_by << 'ELSE 1 END'
order(order_by.join(' '))
}
end

在controller中调用了该scope。刷新页面后,发现服务器报出warning message:

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "CASE WHEN id in (4,6,9) THEN 0 ELSE 1 END". 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().

解决方法

其实,报错信息里面已经告诉我解决方法了,但是当时一看懵逼,Dangerous query method?!直接Google了一堆,后面在slack上跟同事求助了下,搞定!

很简单,就是使用warning message里面提到的Arel.sql()方法,将CASE WHEN id in (4,6,9) THEN 0 ELSE 1 END 用Arel.sql() 包起来即可。

修改scope:

class Issue < ApplicationRecord
.........
IDLIST = [4, 6, 9]
scope :order_by_custom_id, -> {
order_by = ['CA 大专栏  Dangerous query method called with non-attribute argument(s)SE']
order_by << "WHEN id in (#{IDLIST.join(', ')}) THEN 0"
order_by << 'ELSE 1 END'
order(Arel.sql(order_by.join(' ')))
}
end

OK!

但是,这个Arel.sql(raw_sql)是什么?

先看看Arel是什么。

官方文档的解释:

Arel is a SQL AST manager for Ruby. It

  • Simplifies the generation of complex SQL queries
  • Adapts to various RDBMSes

文档里面还列出了很多例子,从简单的select * from users 到复杂点的joins table,我猜是因为我接触Rails的时间不长,反正是从来没用过这东西。

Arel.sql(raw_sql) 这个类方法的源代码如下:

def self.sql raw_sql
Arel::Nodes::SqlLiteral.new raw_sql
end

也就是新建了一个Arel::Nodes::SqlLiteral实例,而Arel::Nodes::SqlLiteral为什么是安全的呢?用Arel::Nodes::SqlLiteral 把raw_sql包起来的用意是什么?估计也能猜到,防攻击啥的。果然,Google了下,发现说是可以防止SQL注入的情况。

有些复杂了,脑子暂时消化不了。

此外,文档中有关sanitize_limit 部分也有提到SQL injection的问题。

参考

Arel

A “strict Arel” mode for ActiveRecord to prevent SQL injection vulnerabilities

Dangerous query method called with non-attribute argument(s)的更多相关文章

  1. C#编译问题'System.Collections.Generic.IEnumerable' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument

    &apos;System.Collections.Generic.IEnumerable<string>&apos; does not contain a definiti ...

  2. 【spring data jpa】repository中使用@Query注解使用hql查询,使用@Param引用参数,报错:For queries with named parameters you need to use provide names for method parameters. Use @Param for query method parameters, or when on

    在spring boot中, repository中使用@Query注解使用hql查询,使用@Param引用参数 如题报错: For queries with named parameters you ...

  3. 编译问题:'<invalid-global-code>' does not contain a definition for 'Store' and no extension method 'XXX' accepting a first argument of type '<invalid-global-code>' could be found

    这是VS2015上的bug. 我碰到的时候,是VS在合并两个分支的代码时,多加了一个}.导致编译语法报错.. 解决办法就是在错误的附近,找找有没有多余的大括号,删掉即可. 这个问题在vs2017上面没 ...

  4. 深入浅出Attribute(三)

    约定: 1.”attribute”和”attributes”均不翻译 2.”property”译为“属性” 3.msdn中的原句不翻译 4.”program entity”译为”语言元素” Attri ...

  5. Using dojo/query(翻译)

    In this tutorial, we will learn about DOM querying and how the dojo/query module allows you to easil ...

  6. Segment Tree Query I & II

    Segment Tree Query I For an integer array (index from 0 to n-1, where n is the size of this array), ...

  7. Lintcode: Segment Tree Query II

    For an array, we can build a SegmentTree for it, each node stores an extra attribute count to denote ...

  8. Lintcode: Segment Tree Query

    For an integer array (index from 0 to n-1, where n is the size of this array), in the corresponding ...

  9. Attribute的理解和认识

    1什么是Attribute? 在网上看到这样一段定义 MADN的定义为:公共语言运行时允许添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法和属性等.A ...

随机推荐

  1. FastReport 使用入门 (二)

    上部分  我们将格式大概都画好了 下面 我们将Datatable的每列绑定到  我们添加的table控件上 .然后打开table控件的事件 双击选中 ManualBuild 事件 添加代码 priva ...

  2. 第04项目:淘淘商城(SpringMVC+Spring+Mybatis)【第九天】(商品详情页面实现)

    https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040 ...

  3. More 'long-life' plastic bags being used

    1 1.1 roll out v. 推广,或实行 1.2 pilot v. 试行 n. 飞行员 1.3 bags for life 可重复使用的环保购物袋 2 2.1 How many times a ...

  4. 在gff中切fa的内容

    #!/usr/bin/python import re def readfa(l): col={} arr =[] sca ='' li = open(l) for line in li: if re ...

  5. HDU-3974 Assign the task(多叉树DFS时间戳建线段树)

    http://acm.hdu.edu.cn/showproblem.php?pid=3974 Time Limit: 15000/5000 MS (Java/Others)    Memory Lim ...

  6. js 判断元素的display是否为block或者none

    if($(this).css("display")=="none"){ //隐藏的 }else{ //显示的 }

  7. oracle ORA-01461 错误 can bind a LONG value only for insert into a LONG column

    我的ORACLE表里没有long字段,可是保存时报错:  ORA-01461 :仅可以为插入LONG列的LONG值赋值  本来我这张表里只有一个VARCHAR2(4000)的字段,一直没有这种错误发生 ...

  8. 调用支付JSAPI缺少参数:sign

    微信jsapi调用微信支付时报 :调用支付JSAPI缺少参数:sign 这个问题我查了很久,最后把前端的代码也拿过来看来,发现前端 sign的参数名传错了~~~~~~~前后端分离很容易出现这种问题,对 ...

  9. Linux命令:ldd

    1.ldd不是一个可执行程序,而是一个shell脚本. zlf@ubuntu:~/$ which ldd /usr/bin/ldd zlf@ubuntu:~/$ file /usr/bin/ldd / ...

  10. 关于MyBatis的运行原理(转载)

    1.获取sqlSessionFactory对象: 解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSessionFactory: 注意: ...