如果你想写一个棘手的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