Ruby中使用<<-SQL编写查询如何传参并返回ActiveRecord Relation?
问题1:SQL块中变量的正确引用方式
- 你当前的变量引用语法是错误的,Ruby的heredoc语法不会自动识别SQL语句内部的
my_limit、my_offset为外部传入的变量,执行时会被当做SQL常量/字段名处理,直接报错。 - 禁止直接使用
#{my_limit}这类字符串插值方式注入变量,会存在严重的SQL注入风险,需要用Rails提供的参数绑定能力安全传入变量,参考写法:
# 用占位符做参数绑定 bound_sql = ActiveRecord::Base.sanitize_sql_array([ <<~SQL, my_limit, my_offset SELECT * FROM my_table ORDER BY id LIMIT ? OFFSET ? SQL ])
- 额外提示:你当前写的SQL语句顺序有误,
ORDER BY id需要放在LIMIT、OFFSET之前,否则会触发SQL语法错误。
问题2:返回MyTable模型对应的Relation对象
- 不要使用
MyTable.find_by_sql执行上述SQL,该方法返回的是模型实例数组,不是Relation对象,无法后续链式调用ActiveRecord查询方法。 - 根据你的场景,推荐两种实现方案:
- 方案1(优先推荐):无需手写原生SQL,直接使用ActiveRecord内置查询方法链式调用,天然返回Relation对象:
def get_relation(my_offset, my_limit) MyTable.order(id: :asc).limit(my_limit).offset(my_offset) end- 方案2(必须使用自定义原生SQL的场景):将绑定好参数的原生SQL作为子查询,通过
from方法构建Relation:
def get_relation(my_offset, my_limit) bound_sql = ActiveRecord::Base.sanitize_sql_array([ <<~SQL, my_limit, my_offset SELECT * FROM my_table ORDER BY id LIMIT ? OFFSET ? SQL ]) MyTable.from("(#{bound_sql}) AS my_tables") end
内容的提问来源于stack exchange,提问作者amggg013
相关产品推荐
相关产品推荐

