Ruby on Railsの特定のActiveRecordクエリによって生成されるSQLを確認するにはどうすればよいですか


116

特定のActiveRecordクエリが生成するSQLステートメントを見たいのですが。クエリが発行された後、ログからこの情報を取得できることを認識していますが、ActiveRecordクエリで呼び出すことができるメソッドがあるかどうか疑問に思っています。

例えば:

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

irbコンソールを開き、このクエリが生成するSQLを表示するメソッドを最後に追加しますが、必ずしもクエリを実行するわけではありません。

回答:


12

最後にこれをやろうとしたとき、公式な方法はありませんでした。私はfindそのクエリとその友達が直接クエリを生成するために使用する関数を使用しました。これはプライベートAPIであるため、Rails 3が完全にそれを壊すという大きなリスクがありますが、デバッグには問題ありません。

メソッドはconstruct_finder_sql(options)lib/active_record/base.rb:1681)ですsend。プライベートであるため、使用する必要があります。

編集construct_finder_sql Rails 5.1.0.beta1で削除されました


1
これは私が考えていることとほぼ同じです。私は人が次のようなことをするプラグインを書くことができると思います:SampleModel.find(:all、:select => "DISTINCT(*)" date、:conditions => [" >#{self.date}"]、:limit => 1、:order => ' date'、:group => " date").show_generated_sqlそしてこれがconstruct_finder_sqlメソッドを呼び出すようにします。
rswolff 2009

1
DataMapperを使用すると、クエリをすぐに実行しないため、それが可能です。一方、ActiveRecordはクエリをすぐに実行します。 show_generated_sqlから既に取得されたデータセットに作用しますfind
ジョンF.ミラー

4
Rails 3 construct_finder_sqlでは実際に削除されています
Veger

190

pengerに似ていますが、クラスがロードされ、ロガーがキャッシュされた後でも、コンソールでいつでも機能します。

Rails 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

これはで機能しませんrails console。シェルから直接ロードされたirbに対してのみ機能しますか?(またはレール3で削除されましたか?)
Eric Hu

2
彼らはそれをRails 3のより適切な場所に移動しました...私の更新されたバージョンを参照してください。
GTD 2011

コンソールを起動するたびにこれを自動的に行う方法はありますか?beforeロードフックのようなものですか?
stream7

1
@ stream7 environment.rb.. if "irb" == $0;ActiveRecord::Base.logger = Logger.new(STDOUT);end私は今これが必要かどうかわかりませんが、このコードを..に移動できます。http:
rubyprince

これは質問に答えません:クエリを実行せずにデバッグ中に特定のクエリのSQLを表示する方法。
bradw2k 2016

87

puts query_object.classどこかに突き刺して作業しているオブジェクトのタイプを確認し、ドキュメントを検索します。

たとえば、Rails 3.0では、スコープActiveRecord::Relation#to_sqlメソッドを持つwhichを使用します。例えば:

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

次に、あなたができるどこか:

puts Contact.frequently_contacted.to_sql

3
なぜこの回答は賛成されないのですか?Rails 3の場合、これはより良い答えです。末尾に「.to_sql」を置くだけで、任意のAR :: Relationステートメントの結果を取得できます。この質問は、その答えを提供します。stackoverflow.com/questions/3814738/...
スティーブ・ミジリー

5
注意:includes関係にある場合、すべてのSQLを取得することはできません
Barry Kelly

3
@BarryKellyなぜですか?
Vishnu Narang 2016年

25

これは古い質問かもしれませんが、私は使用します:

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

このexplainメソッドは、それが何をするかについて非常に詳細なSQLステートメントを提供します


3
また、記録のためだけに、クエリが実行されます。
イブラヒム

22

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"

11

これは、コンソールでSQLを生成するために私が通常行うことです

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

コンソールを最初に起動するときにこれを実行する必要があります。コードを入力した後にこれを実行すると、機能しないようです

本当にこれを信用することはできません、誰かのブログからずっと前にそれを見つけました、そしてそれが誰であるか思い出せません。


1
:私はかなり確信して、それがJamisバックのブログだったんだweblog.jamisbuck.org/2007/1/8/...
rswolff

1
それが原因でRails 2.3が原因かどうかはわかりませんが、これは私にはうまくいきません。以下の私の応答を参照してください。
gtd 2009年

これは優れたソリューションIMOです。
ベンジャミンアトキン2014

10

ホームディレクトリに.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 :: Relationを返し、.to_sqlを呼び出す限り、スコープ/メソッドを構築でき、実行されるSQLが出力されます。


これは私がやっていることですが、ActiveRecordクエリが生成する予測されたSQLを単に見ることに興味があります。これを行う簡単な方法がないことに驚いています...
rswolff

5

それが使用するSQLを確認するための私の典型的な方法は、SQLに「バグ」を導入することです。そうすると、問題のSQLを含む通常のロガー(およびWeb画面)にエラーメッセージが出力されます。stdoutが進んでいる場所を見つける必要はありません...


1
壮大しかし、最速のソリューション:)
JANJanočko

2

show_sqlプラグインを試してください。プラグインを使用すると、SQLを実行せずに印刷できます

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

1
リンクが壊れたようです(404エラー)。おそらく、Ryan Biggがプラグインを削除しました。
DNNX 2012年

1

接続のログメソッドを変更して例外を発生させ、クエリが実行されないようにすることができます。

それは完全なハックですが、私にとってはうまくいくようです(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

0

Rails 3では、この行をconfig / environments / development.rbに追加できます

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

ただし、クエリは実行されます。しかし、半分は答えられました:

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.