在 Ruby on Rails 中,如何查看给定 ActiveRecord 查询将生成的 SQL

我希望看到给定 ActiveRecord 查询将生成的 SQL 语句。我知道在发出查询之后我可以从日志中获得这些信息,但是我想知道是否有一个可以调用的方法和 ActiveRecord Query。

例如:

SampleModel.find(:all, :select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")

我想打开 irb 控制台,并在最后添加一个方法,该方法将显示此查询将生成的 SQL,但不一定执行该查询。

94188 次浏览

在主目录中创建一个. irbrc 文件,并将其粘贴到:

if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
require 'logger'
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
end

这将在您执行时将 SQL 语句输出到 irb 会话中。

编辑: 对不起,这将仍然执行查询,但它是最接近我所知道的。

编辑: 现在使用 arel,只要对象返回 ActiveRecord: : Relations 和 call,就可以构建作用域/方法。To _ sql,它将输出将要执行的 sql。

上次我尝试这么做的时候,没有正式的方法。我使用了 find和它的朋友使用的函数来直接生成他们的查询。它是私有 API,所以 Rails 3完全破坏它的风险很大,但是对于调试来说,这是一个不错的解决方案。

这个方法是 construct_finder_sql(options)(lib/active_record/base.rb:1681) ,你必须使用 send,因为它是私有的。

编辑 : construct_finder_sql 在 Rails5.1.0. beta1中删除

您可以更改连接的 log 方法以引发异常,从而阻止查询运行。

这是一个彻头彻尾的黑客行为,但似乎对我有效(Rails 2.2.2,MySQL) :

module ActiveRecord
module ConnectionAdapters
class AbstractAdapter
def log_with_raise(sql, name, &block)
puts sql
raise 'aborting select' if caller.any? { |l| l =~ /`select'/ }
log_without_raise(sql, name, &block)
end
alias_method_chain :log, :raise
end
end
end

这就是我通常在控制台中生成 SQL 的方法

-> script/console
Loading development environment (Rails 2.1.2)
>> ActiveRecord::Base.logger = Logger.new STDOUT
>> Event.first

您必须在第一次启动控制台时执行此操作,如果在键入一些代码之后执行此操作,那么它似乎无法工作

这不能归功于你,很久以前在别人的博客上找到的,记不得是谁的了。

与 penger 类似,但是在控制台中任何时候都可以工作,即使类已经加载并且日志记录器已经被缓存:

铁路2:

ActiveRecord::Base.connection.instance_variable_set :@logger, Logger.new(STDOUT)

对于 Rails 3.0. x:

ActiveRecord::Base.logger = Logger.new(STDOUT)

对于 Rails > = 3.1.0,这在默认情况下已经在控制台中完成了。如果太吵,你想 关掉你可以做:

ActiveRecord::Base.logger = nil

尝试使用 Show _ sql 插件。这个插件可以让你在不运行 SQL 的情况下打印 SQL

SampleModel.sql(:select => "DISTINCT(*)", :conditions => ["`date` > #{self.date}"], :limit => 1, :order => '`date`', :group => "`date`")

在某处粘贴一个 puts query_object.class来查看您使用的对象类型,然后查找文档。

例如,在 Rails 3.0中,作用域使用具有 #to_sql方法的 ActiveRecord::Relation:

class Contact < ActiveRecord::Base
scope :frequently_contacted, where('messages_count > 10000')
end

然后,在某个地方你可以做:

puts Contact.frequently_contacted.to_sql

在 Rails 3中,您可以将这一行添加到 config/environment/development.rb

config.active_record.logger = Logger.new(STDOUT)

然而,它将执行查询。但一半得到了回答:

这可能是一个老问题,但我使用:

SampleModel.find(:all,
:select => "DISTINCT(*)",
:conditions => ["`date` > #{self.date}"],
:limit=> 1,
:order => '`date`',
:group => "`date`"
).explain

explain方法将提供关于它要做什么的相当详细的 SQL 语句

查看 sql 使用什么的典型方法是在 sql 中引入一个“ bug”,然后您将得到一条错误消息,这条消息将发送给存在 sql 问题的普通日志记录器(和 web 屏幕)。不需要知道 stdout 的去向。

只要使用 to_sql方法,它就会输出将要运行的 sql 查询。它对活动记录关系起作用。

irb(main):033:0> User.limit(10).where(:username => 'banana').to_sql
=> "SELECT  "users".* FROM "users"  WHERE "users"."username" = 'banana'
LIMIT 10"

当执行 find时,它不会工作,因此您需要手动将 id 添加到查询中,或者使用 where 运行它。

irb(main):037:0* User.where(id: 1).to_sql
=> "SELECT "users".* FROM "users"  WHERE "users"."id" = 1"

您可以简单地使用 to _ sql ()函数处理活动记录

Form.where(status:"Active").to_sql