Rails7升级后sanitize_sql_array将数值转为字符串,求解决方法
Rails 7升级后sanitize_sql_array数值被转字符串的解决方法
问题描述
将Rails从6.1升级到7后,调用ActiveRecord::Base.send(:sanitize_sql_array)时,传入的整数、浮点数会被自动转为带引号的字符串,导致SQL语句中的数值运算逻辑异常。
示例代码
输入参数:
updates = ["`bed_count` = `bed_count` + ?", "`operating_room_count` = `operating_room_count` + ?", "`updated_at` = ?"] values = [3.14159, 1, "2022-09-17 18:15:05"]
Rails 7执行结果(数值被加引号):
>> ActiveRecord::Base.send(:sanitize_sql_array, [updates.join(','), *values]) => "`bed_count` = `bed_count` + '3.14159',`operating_room_count` = `operating_room_count` + '1',`updated_at` = '2022-09-17 18:33:44'"
Rails 6.1执行结果(数值保持原样):
"`bed_count` = `bed_count` + 3.14159,`operating_room_count` = `operating_room_count` + 1,`updated_at` = '2022-09-17 18:33:44'"
解决方案
1. 使用sanitize_sql_for_assignment替代
该方法专门用于处理更新语句的赋值逻辑,能正确识别并保留数值类型:
ActiveRecord::Base.send(:sanitize_sql_for_assignment, updates.zip(values).to_h)
执行后会生成正确的SQL片段,数值不会被添加引号。
2. 逐个处理占位符后拼接
循环处理每个更新语句与对应的值,分别调用sanitize后再拼接:
sanitized_updates = updates.zip(values).map do |sql, val| ActiveRecord::Base.send(:sanitize_sql_array, [sql, val]) end.join(',')
这种方式确保每个占位符都被单独正确处理,数值类型得以保留。
3. 使用Arel构建更新语句(推荐)
避免手动拼接SQL,用Arel生成安全的更新逻辑,完全无需手动处理sanitize,同时遵循Rails最佳实践:
table = YourModel.arel_table update_manager = Arel::UpdateManager.new(Arel::Table.engine) update_manager.table(table) update_manager.set([ table[:bed_count].eq(table[:bed_count] + 3.14159), table[:operating_room_count].eq(table[:operating_room_count] + 1), table[:updated_at].eq('2022-09-17 18:15:05') ]) puts update_manager.to_sql
此方法不仅解决数值转字符串问题,还能有效避免SQL注入风险。
内容的提问来源于stack exchange,提问作者Dev V
相关产品推荐
相关产品推荐

