0

アクティブレコード関係の興味深い振る舞いに出会いました。

class A < ActiveRecord::Base
  def self.one
    where("1=1")
  end

  def self.two
    puts A.where("2=2").to_sql
  end

  def self.test
     one.two
  end
end
A.test # prints  ... WHERE 1=1 AND 2=2

Ad.where("2=2") は self.two に "1=1" を含まないと思っていましたが、そうです。特徴ですか?

4

1 に答える 1

2

はい、特徴です。

に渡されたすべての値はwhere、リレーション ( ) によって内部的に格納され、@values[:where]AND で結合されて WHERE ステートメントを構築します。

twoによって返されたリレーションのコンテキストで呼び出すとone、新しいスコープを構築するための基礎として、1 によって格納された「where 値」が使用されます。

以下を使用して、目的の動作を得ることができますunscoped

one.unscoped.two

編集: はい、明らかに奇妙で直感に反しています。

私はちょうどあなたと同じ問題に悩まされました。

掘り下げた結果、Rails 4以降、すべてのモデルは、そのクラス/リレーションで使用されている現在のスコープを格納するスレッドローカルレジストリを保持しているようです. 彼らがなぜそれをしたのか正確にはわかりませんが、私の推測では、それはパフォーマンスに関係しています

ポイントは、すでに一連のスコープをチェーンしており、クラスを参照する別のスコープを呼び出そうとした場合(two例のように)、ActiveRecord はクラスの現在のスコープ、つまり呼び出した関係をフェッチするだけです。そもそもスコープ!かなりばかげています。実際、クラス参照twoなしでメソッドを書き直すことができますが、何も変更されません。A

奇妙で奇妙なことに、 STI を使用すると別の問題が発生しました。私のスコープでは、 を使用して親モデルにまったく関係のない呼び出しを行いましたpluck。この「機能」は予期しない方法でクエリに影響を与えただけでなく、デフォルトのスコープも「リセット」しているように見えるため、次のクエリ (スコープの実際の戻り値) は、前のクエリによって渡されたすべての条件を「忘れて」しまいました。スコープ... なんだ?

結論: Rails github でチケットを開き、少なくともチームにこの奇妙な動作を文書化するよう依頼する必要があると思います。(MyClass.unscoped最初のクエリで使用すると問題は解決しましたが、直感的ではありません)

于 2013-10-24T12:10:27.357 に答える