使用`to_sql`查看ActiveRecord将生成什么查询。

72 阅读1分钟

如果你想写一个棘手的ActiveRecord查询,包括joins ,复杂的where 子句,或者在不同的表中选择特定的值,那么要记住ActiveRecord DSL的每一部分是很困难的。

joins(:orders) 还是joins(:order) ?你应该使用where(role: { name: 'Manager' }) 还是where(roles: { name: 'Manager' })

在Rails控制台测试这些查询是个好主意,这样你就可以快速迭代,但有时你会抓耳挠腮,因为当你运行代码时,你会得到一个奇怪的结果,比如。

#<MyModel::ActiveRecord_Relation:0x23118>

而如果你试图访问这些结果,查询就会出现一个神秘的错误,如:。

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "permission"
LINE 1: ...."id" = "permissions_users"."permission_id" WHERE "permissio...

使用方法

有时你只想检查生成的SQL,以调试出错的地方。

其实用ActiveRecord很容易做到这一点:只需在你的查询上调用to_sql ,它就会打印出完整的查询,而不是运行SQL,即使SQL无效。

User.where("email LIKE '%?'", "gmail.com").to_sql
=> "SELECT \"users\".* FROM \"users\" WHERE (email LIKE '%'gmail.com'')"

啊哈!我们把%? 的语法弄乱了。

User.where("email LIKE ?", "%gmail.com").to_sql
=> "SELECT \"users\".* FROM \"users\" WHERE (email LIKE '%gmail.com')"

如果你涉及到多个数据库表,它就特别有用。

User.joins(:permissions).where(permission: { key: :edit_posts }).to_sql
=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"permissions_users\" ON \"permissions_users\".\"user_id\" = \"users\".\"id\" INNER JOIN \"permissions\" ON \"permissions\".\"id\" = \"permissions_users\".\"permission_id\" WHERE \"permission\".\"key\" = 'edit_posts'"

糟糕!我们需要使用复数的。我们需要在我们的where 中使用复数的permissions

User.joins(:permissions).where(permissions: { key: :edit_posts })

这个技巧为我节省了无数调试复杂查询的时间。我还用它来验证棘手的查询,以确保Rails生成的是预期的SQL查询。

其他资源

Rails API。ActiveRecord::Relation#to_sql