web-dev-qa-db-ja.com

Rails default_scopeのオーバーライド

デフォルトスコープを持つActiveRecord :: Baseモデルがある場合:

class Foo < ActiveRecord::Base

  default_scope :conditions => ["bar = ?",bar]

end

Foo.find条件を使用してdefault_scopewithoutを実行する方法はありますか?つまり、デフォルトのスコープをオーバーライドできますか?

名前に「デフォルト」を使用すると、それがwasオーバーライド可能であることを示唆していると思います。そうでなければ、global_scopeのようなものと呼ばれますよね?

148
Gareth

簡単な答え:本当に必要な場合以外は、default_scopeを使用しないでください。おそらく、名前付きスコープの方が良いでしょう。そうは言っても、必要に応じてwith_exclusive_scopeを使用してデフォルトのスコープをオーバーライドできます。

詳細については この質問 をご覧ください。

149
Pär Wieslander

Rails 3:

foos = Foo.unscoped.where(:baz => baz)
211
Vincent

必要なのがdefault_scopeで定義された順序を変更するだけである場合は、 reorder method を使用できます。

class Foo < ActiveRecord::Base
  default_scope order('created_at desc')
end

Foo.reorder('created_at asc')

次のSQLを実行します。

SELECT * FROM "foos" ORDER BY created_at asc
104
GuiGS

4.1から ActiveRecord::QueryMethods#unscope を使用してデフォルトのスコープと戦うことができます:

class User < ActiveRecord::Base
  default_scope { where tester: false }
  scope :testers, -> { unscope(:where).where tester: true }
  scope :with_testers, -> { unscope(:where).where tester: [true, false] }
  # ...
end

現在、:where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :havingのようなunscopeが可能です。

ただし、可能であればdefault_scopeの使用は避けてください。それはあなた自身のためです。

47
jibiel

with_exclusive_scopeメソッドを使用して、デフォルトのスコープをオーバーライドできます。そう:

foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }
14
John Topley

Rails 3のdefault_scopeは、Rails 2のようにオーバーライドされるようには見えません。

例えば.

class Foo < ActiveRecord::Base
  belongs_to :bar
  default_scope :order=>"created_at desc"
end

class Bar < ActiveRecord::Base
  has_many :foos
end

> Bar.foos
  SELECT * from Foo where bar_id = 2 order by "created_at desc";
> Bar.unscoped.foos
  SELECT * from Foo;  (WRONG!  removes the "has" relationship)
> Bar.foos( :order=>"created_at asc" )  # trying to override ordering
  SELECT * from Foo where bar_id = 2 order by "created_at desc, created_at asc"

私のアプリでは、PostgreSQLを使用して、デフォルトのスコープでの順序はWINSです。 default_scopesをすべて削除し、どこでも明示的にコーディングしています。

Pitfall Rails3!

5
vanboom

Rails 3+では、対象範囲外とマージの組み合わせを使用できます。

# model User has a default scope
query = User.where(email: "[email protected]")

# get rid of default scope and then merge the conditions
query = query.unscoped.merge(query)
5
santervo

さて、いつでも完全なクエリで昔のお気に入りfind_by_sqlを使用できます。例:Model.find_by_sql( "SELECT * FROM models WHERE id = 123")

2
Ady Rosen