Rails Geçersiz Kılma default_scope


156

Varsayılan kapsamı olan bir ActiveRecord :: Base modelim varsa:

class Foo < ActiveRecord::Base

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

end

Bir yapmak için herhangi bir yolu var mı Foo.find olmadan kullanan default_scopekoşulları? Başka bir deyişle, varsayılan bir kapsamı geçersiz kılabilir misiniz?

Ben adında 'varsayılan' kullanarak onu öneririm düşünürdü oldu aksi takdirde böyle bir şey aranmak, geçersiz kılınabilir global_scopesağ?


Yanıtlar:


151

Kısa cevap: Gerçekten gerekmedikçe kullanmayın default_scope. Muhtemelen adlandırılmış kapsamlarla daha iyi olacaksınız. Bununla birlikte, gerekirse with_exclusive_scopevarsayılan kapsamı geçersiz kılmak için kullanabilirsiniz.

Daha fazla ayrıntı için bu soruya bir göz atın .


Önceki soruya olan bağlantı için teşekkürler
Gareth

10
> Gerçekten gerekmedikçe default_scope kullanmayın. Mükemmel bir tavsiye! Teşekkür ederim!
installero

2
Çok doğru. Kullanmak default_scopeiyi bir fikir gibi görünebilir, ancak muhtemelen uygulamanızın ömrü boyunca birden fazla baş ağrısına neden olacaktır.
thomax


1
Biraz abartıyorsunuz efendim. default_scopemükemmel bir araçtır ve başka bir yoldan yapabileceğiniz durumlar vardır, ancak default_scopebunun yapılması gereken doğru şeydir. Örneğin, bayrağı Productolan bir modeliniz olduğunda, % 99'luk veya vakalardan etkin olmayan bir ürün görüntülemek istemeyeceğiniz için a'nın inactiveayarlanması default_scope { where inactive: false }en iyi şeydir. Ardından unscoped, kalan% 1'lik vakaları çağırırsınız , bu da büyük olasılıkla Yönetici panelidir.
pedrozath

215

Raylar 3'te:

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

58
Post has_many Comment, Post.first.comments.unscoped TÜM yorumları döndürürse, bunun bir yan etkisi vardır.
Enrico Carlesso

3
Bu beni bir süre berbat etti. Özellikle bunu şöyle bir sınıf yöntemine yerleştirirseniz: def self.random; unscoped.order('rand()'); enduncoped, yalnızca default_scope altında listelenenleri değil, TÜM sql'yi ondan önce kaldırır. Teknik olarak doğru bir cevap olsa da, dikkatli olununstopped
Schneems

7
UYARI! Kaplanmamış, yalnızca default_scope'u SİLMEZ, başka bir yorumda zaten söylendi, ancak gerçekten şeylerle uğraşabilir.
dsimard

15
İyi bir kural, sadece unscopedbir modeli doğrudan takip edebildiğinde, örneğin Foo.unscoped.blah()tamam ama asla Foo.blah().unscoped.
Grant Birchmeier

stackoverflow.com/questions/1834159/… Enrico tarafından belirtilen yan etki etrafında çalışır
wbharding

107

İhtiyacınız olan tek şey, tanımlanan sırayı değiştirmekse default_scope, reorderyöntemi kullanabilirsiniz .

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

Foo.reorder('created_at asc')

aşağıdaki SQL'i çalıştırır:

SELECT * FROM "foos" ORDER BY created_at asc

3
İpucu: gibi bir kapsam tanımlayın scope :without_default_order, -> { reorder("") }ve böyle şeyler yapabilirsiniz Foo.without_default_order.order("created_at ASC")Bazı durumlarda daha iyi okur (belki de tam olarak bu durum değil, ama bir tane vardı).
Henrik N

Yeniden sıralamayı benim için yaptı. Çok teşekkürler!
Andre Zimpel

49

Yana 4.1kullanabilirsiniz ActiveRecord::QueryMethods#unscopevarsayılan kapsamını mücadele:

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

Öyle anda mümkün unscopegibi şeylerle: :where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :having.

Ama yine de default_scopeeğer yapabilirseniz kullanmaktan kaçının . Bu kendi iyiliğin için.


Bu cevap daha yüksek olmalı
Stephen Corwin


5

Rails 3 default_scope, Rails 2'deki gibi geçersiz kılınmış gibi görünmüyor.

Örneğin

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"

Benim app PostgreSQL kullanarak, varsayılan kapsam WINS sipariş. Tüm default_scopes tüm kaldırma ve açıkça her yerde kodlama.

Tuzak Rayları3!


1
Kullanmanız gerekirBar.foos.reorder(:created_at => :asc)
Ivan Stana

5

Rails 3+ ile, birleştirilmemiş ve birleştirmenin bir kombinasyonunu kullanabilirsiniz:

# 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)

Bu da benim için ilk önce örtümsüz olarak adlandırmak için çalıştı (Rails 4.2):User.unscoped.where(email: "foo@example.com")
Nick

4

Rails 5.1+ (ve belki de daha önce, ancak 5.1 üzerinde çalıştığını test ettim) belirli bir sütunu çıkarmak mümkündür, bu imho, default_scopeadlandırılmış bir kapsamda kullanılabilecek bir şekilde kaldırmak için ideal bir çözümdür . OP'ler söz konusu olduğunda default_scope,

Foo.unscope(where: :bar)

Veya

scope :not_default, -> { unscope(where: :bar) }
Foo.not_default

Her ikisi de orijinal kapsamı uygulamayan, ancak arel ile birleştirilen diğer koşulları uygulayan bir sql sorgusuyla sonuçlanır.


2

Eh, her zaman find_by_sqltam sorgu ile eski zaman favori kullanabilirsiniz . Örneğin: Model.find_by_sql ("SELECT * KİMDEN modeller İLE ID = 123")

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.