重写Rails的default_scope
如果我有一个默认范围的ActiveRecord :: Base模型:
class Foo < ActiveRecord::Base default_scope :conditions => ["bar = ?",bar] end
有没有办法做一个Foo.find
而不使用default_scope
条件? 换句话说,你可以重写一个默认的作用域?
我会认为在名称中使用“默认”会暗示它是可覆盖的,否则将被称为像global_scope
,对吗?
简短的回答:除非你真的需要,否则不要使用default_scope
。 你可能会更好的命名范围。 这样说,你可以使用with_exclusive_scope
覆盖默认的作用域,如果你需要。
看看这个问题的更多细节。
在Rails 3中:
foos = Foo.unscoped.where(:baz => baz)
如果您只需要更改default_scope
定义的顺序,则可以使用reorder
方法 。
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
从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
目前有可能unscope
像:: :where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :having
。
但是如果可以的话,仍然请避免使用default_scope
。 这是为了你自己的好。
您可以使用with_exclusive_scope
方法覆盖默认作用域。 所以:
foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }
-
with_exclusive_scope
文档
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,在默认范围内sortingWINS。 我删除了我所有的default_scopes,并在各处显式编码。
陷阱Rails3!
使用Rails 3+,您可以使用unscoped和merge的组合:
# model User has a default scope query = User.where(email: "foo@example.com") # get rid of default scope and then merge the conditions query = query.unscoped.merge(query)
那么,你可以随时使用旧时间最喜欢的find_by_sql
和完整的查询。 例如:Model.find_by_sql(“SELECT * FROM models WHERE id = 123”)