mysql - 使用 JOIN 时 ActiveRecord 查询中 ORDER 的动态方向

标签 mysql ruby-on-rails ruby ruby-on-rails-4 activerecord

我正在尝试清理一些被标记为易受 SQL 注入(inject)攻击的代码。因此,我将大量原始 SQL 查询字符串转换为 ActiveRecord 的方法。当我想将排序 (order) 应用于嵌套属性时,我在寻找等效查询时遇到了问题。

如果我有一个 AccountUser 对象,并且我想按 user_id 对结果进行排序,我可以 这样做(这是目前的代码):

->(direction) { Account.joins(:users).order("users.id #{direction}").first }

但是,这很容易受到 SQL 注入(inject)攻击。

我知道,如果我按 Account 的属性进行排序,您只需将哈希传递给 order

->(direction) { Account.joins(:users).order(created_at: direction).first }

但是,使用字符串作为排序依据的属性(因为它是嵌套的)不会产生正确的查询:

->(direction) { Account.joins(:users).order('users.id': direction).first }
# SELECT  `accounts`.* FROM `accounts` INNER JOIN `users` ON `users`.`account_id` = `accounts`.`id`  ORDER BY `accounts`.`users.id` DESC LIMIT 1

并且使用嵌套散列也不起作用

->(direction) { Account.joins(:users).order(users: {id: direction}).first }

我知道我可以通过一些额外的逻辑强制 direction 成为可接受的值之一,但我想知道是否有一种简单的方法可以通过我遗漏的 ActiveRecord 查询来做到这一点。

最佳答案

我担心只能通过字符串支持通过加入的协会进行排序。

但是,有可能merge允许你写的范围:

->(direction) { Account.joins(:users).merge(User.order(id: direction})).first }

这确实会阻止 [:asc, :desc, :ASC, :DESC, "asc", "desc", "ASC", "DESC"] 以外的方向值(摘自ArgumentError 消息)。在我看来,这是以降低可读性为代价的,但可以通过将顺序定义为 User 类中的命名范围来尝试缓解问题并同时提高可重用性。

class User
   ...
   self.ordered_by_id(direction)
     order(id: direction})
   end
   ...
end

这使您能够使用

->(direction) { 
  Account.joins(:users).merge(User.ordered_by_id(direction)).first
} 

诚然,在当前示例中这还没有发挥作用,但是使用具有更复杂范围的 merge 可以大大减少重复。

关于mysql - 使用 JOIN 时 ActiveRecord 查询中 ORDER 的动态方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46394845/

相关文章:

ruby-on-rails - Heroku-toolbelt 安装在我的 mac OS X 中出错

ruby-on-rails - ruby 中 CSV.open( ) 的第二个参数/参数是什么?

ruby - Time.now 与 Controller 的 Rails 问题

php - 在 MySQL/PHP 中检索和插入多个条目

mysql - 唯一表的总和

mysql - 优化 ORDER BY 使用列从左连接 MySql

ruby-on-rails - 具有用户身份验证功能的 Rails Web 应用程序是否有 'template' ?

php - MySQL和PHP基于时间的频率

jquery - Ruby on Rails - jQuery 事件无法正常工作

ruby-on-rails - 将多个用户添加到单个记录中 Rails 5