9

これはRails 3のバグだと思います。ここの誰かが私を正しい方向に導いてくれることを願っています。以下に掲載されているコードは、この問題を説明するためのものです。これで問題が混乱しないことを願っています。

Post モデルと Comment モデルがあるとします。投稿には has_many のコメントがあり、コメントは投稿に属しています。

Post モデルに default_scope を設定し、joins() と where() の関係を定義します。この場合、where() は joins() に依存しています。

通常、投稿はコメントに依存しません。繰り返しますが、簡単な例を挙げたいと思います。これは、where() が joins() に依存している場合に当てはまります。

class Post < ActiveRecord::Base
  has_many :comments, :dependent => :destroy

  default_scope joins(:comments).where("comments.id < 999")
end

class Comment < ActiveRecord::Base
  belongs_to :post, :counter_cache => true
end

次のコマンドを実行します。

Post.update_all(:title => Time.now)

次のクエリを生成し、最終的に ActiveRecord::StatementInvalid をスローします。

UPDATE `posts` SET `title` = '2010-10-15 15:59:27'  WHERE (comments.id < 999)

繰り返しますが、update_all、delete_all、destroy_all は同じように動作します。counter_cache を更新しようとしたときにアプリケーションが不平を言ったときに、この動作を発見しました。最終的に update_all にドリルダウンします。

4

4 に答える 4

7

update_all私もこの問題を抱えていましたが、複雑な条件で使用できる必要がありましたdefault_scope(たとえば、デフォルトのスコープなしでは積極的な読み込みは不可能であり、名前付きスコープを文字通りどこにでも貼り付けるのはまったく楽しいことではありません)。私はここで私の修正でプルリクエストを開きました:

https://github.com/rails/rails/pull/8449

delete_allの場合、何をしなければならないかをより明確にするために結合条件がある場合にエラーが発生しました(結合条件を投げてすべてに対してdelete_allを実行する代わりに、エラーが発生します)。

レールの連中が私のプルリクエストで何をするのかわからないが、それはこの議論に関連していると思った。(また、このバグを修正する必要がある場合は、私のブランチを試して、プルリクエストにコメントを投稿することができます。)

于 2012-12-07T13:27:40.360 に答える
4

私もこれに出くわしました

あなたが持っている場合

class Topic < ActiveRecord::Base
  default_scope :conditions => "forums.preferences > 1", :include => [:forum]
end

そして、あなたは

Topic.update_all(...)

それは失敗します

Mysql::Error: Unknown column 'forums.preferences' in 'where clause'

これに対する回避策は次のとおりです。

Topic.send(:with_exclusive_scope) { Topic.update_all(...) }

このコードを使用してこれにモンキー パッチを適用できます (さらに、environment.rb またはその他の場所でそれを要求します)。

module ActiveRecordMixins
  class ActiveRecord::Base
    def self.update_all!(*args)
      self.send(:with_exclusive_scope) { self.update_all(*args) }
    end
    def self.delete_all!(*args)
      self.send(:with_exclusive_scope) { self.delete_all(*args) }
    end
  end
end

終わり

それならあなただけ update_all! またはdelete_all! デフォルトのスコープがある場合。

于 2011-02-05T00:03:21.993 に答える
1

次のように、新しいメソッドを作成せずに、クラス レベルでこれを行うこともできます。

def self.update_all(*args)
  self.send(:with_exclusive_scope) { super(*args) }
end

def self.delete_all(*args)
  self.send(:with_exclusive_scope) { super(*args) }
end
于 2012-08-28T18:58:29.893 に答える
0

バグとは呼べないと思います。すぐには明らかではありませんが、動作は私には十分に論理的に思えます。しかし、うまく機能しているように見える SQL ソリューションを考え出しました。あなたの例を使用すると、次のようになります。

class Post < ActiveRecord::Base
  has_many :comments, :dependent => :destroy

  default_scope do
    with_scope :find => {:readonly => false} do 
      joins("INNER JOIN comments ON comments.post_id = posts.id AND comments.id < 999")
    end
  end
end

実際には、リフレクションを使用してより堅牢にしていますが、上記のアイデアは矛盾しています。WHERE ロジックを JOIN に移動すると、不適切な場所に適用されなくなります。オプションは、 'd オブジェクトを読み取り専用にするという:readonlyRails のデフォルトの動作に対抗することです。joins

また、 の使用を嘲笑する人がいることも知っていますdefault_scope。しかし、マルチテナント アプリの場合は、これが最適です。

于 2013-03-21T17:27:45.820 に答える