Neden default_scope kullanılmaması tavsiye edilir raylar?


127

Her yer üzerinde internet insanların raylar kullanarak söz kötü bir fikir olduğunu ve üst hit stackoverflow üzerine yazmak konusunda bulunmaktadır. Bu berbat hissettiriyor ve açık bir soruyu hak ediyor (sanırım).default_scopedefault_scope

Öyleyse: neden rayları kullanmamalıyız default_scope?

Yanıtlar:


192

Problem 1

Temel örneği ele alalım:

class Post < ActiveRecord::Base
  default_scope { where(published: true) }
end

Varsayılanı published: trueyapmanın motivasyonu , yayınlanmamış (özel) gönderileri göstermek istediğinizde açık olmanız gerektiğinden emin olmak olabilir. Çok uzak çok iyi.

2.1.1 :001 > Post.all
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."published" = 't'

Pekala, beklediğimiz şey bu. Şimdi deneyelim:

2.1.1 :004 > Post.new
 => #<Post id: nil, title: nil, published: true, created_at: nil, updated_at: nil>

Ve orada varsayılan kapsamla ilgili ilk büyük sorunumuz var:

=> default_scope, model başlatmanızı etkileyecektir

Böyle bir modelin yeni oluşturulan bir örneğinde, default_scopeyansıtılacaktır. Bu nedenle, yayınlanmamış gönderileri şans eseri listelememek isteyebilirsiniz, ancak artık varsayılan olarak yayınlanmış gönderileri oluşturuyorsunuz.

Problem 2

Daha ayrıntılı bir örnek düşünün:

class Post < ActiveRecord::Base
  default_scope { where(published: true) }
  belongs_to :user
end 

class User < ActiveRecord::Base
  has_many :posts
end

İlk kullanıcıların gönderilerini alalım:

2.1.1 :001 > User.first.posts
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."published" = 't' AND "posts"."user_id" = ?  [["user_id", 1]]

Bu beklenildiği gibi görünüyor (user_id ile ilgili bölümü görmek için en sağa kaydırdığınızdan emin olun).

Şimdi, oturum açmış kullanıcının görünümü için tüm yayınların (yayınlanmamış dahil) listesini almak istiyoruz. Etkisinin 'üzerine yazmanız' veya 'geri almanız' gerektiğini fark edeceksiniz default_scope. Hızlı bir google'dan sonra, muhtemelen öğreneceksiniz unscoped. Sonra ne olacağını görün:

2.1.1 :002 > User.first.posts.unscoped
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"

=> Kapsamlanmamış, ilişkilendirmeler dahil (ancak bunlarla sınırlı olmamak üzere) seçiminiz için normalde geçerli olabilecek TÜM kapsamları kaldırır.

.NET Framework'ün farklı efektlerinin üzerine yazmanın birden çok yolu vardır default_scope. Bunu doğru yapmak çok çabuk karmaşıklaşıyordefault_scope ve ilk etapta kullanmamanın daha güvenli bir seçim olacağını iddia ediyorum.


2
Biriktirmek gerekirse: default_scope'u yararlı bulduğum tek zaman, varsayılan olarak bazı ilişkileri kesinlikle yüklemek istediğiniz zamandır. default_scope {eager_load ([: kategori,: yorumlar])}. Ancak!!! Bu model üzerinde Product.count gibi sayma sorgusu yapıyorsanız, tüm ürünler için eager_load ilişkilendirmeleri yapacaktır. Ve 50K kaydınız varsa, sayma sorgunuz 15 ms'den 500 ms'ye çıktı, çünkü tek istediğiniz saymak olsa da, default_scope diğer her şeye katılacak.
konung

16
Bana göre sorun # 2 unscopedyerine sorunla ilgili görünüyordefault_scope
Kaptan Fogetti

4
@CaptainFogetti Indeed. Yine de kapsamı kaldırılmışın dezavantajlarını default_scope'un olası bir dezavantajı olarak sunmanın iyi bir fikir olduğunu düşünüyorum. Önemsiz olmayan çoğu durumda default_scope kullanmak, kapsamı kaldırılmış kullanmanız gerekmesine neden olacaktır. Bu ikinci derece bir uyarıdır (daha iyi bir terim olmadığı için) ve bir yöntemi araştırırken gözden kaçırmak kolaydır.
wrtsprt

1
Cevabınızdaki kullanım durumuyla ilgili sorun, yayınlanmamış gönderileri bulmak istediğiniz birçok durum olmasıdır. Aslında, yayınlanan yazıları bulmanın özel bir durum olduğunu iddia ediyorum. Gönderilerin yayınlanmasını istediğiniz tek zaman, birisinin genel sayfayı görüntülediği zamandır. Ancak yayınlanmamış gönderileri görmek istediğiniz pek çok zaman vardır.
B Seven

3
Ben iyi bir kullanım tahmin default_scopebir şey sıralanabilir istediğinizde ise: default_scope { order(:name) }.
user2985898

9

Kullanılmadığı için başka bir nedeni default_scopesize bir 1 için birçok ilişkisi olan bir modelin bir örneğini silme yaparken olduğu default_scopemodelin

Örneğin düşünün:

    class User < ActiveRecord::Base
      has_many :posts, dependent: :destroy
    end 

    class Post < ActiveRecord::Base
      default_scope { where(published: true) }
      belongs_to :user
    end

Çağrıldığında user.destroy, var olan tüm postalar silinir published, ancak olan postalar silinmez unpublished. Dolayısıyla, veritabanı kaldırmak istediğiniz kullanıcıya başvuran kayıtları içerdiğinden bir yabancı anahtar ihlali atacaktır.


6

default_scope, bazen sonuç kümesini sınırlamak için yanlış bir şekilde kullanıldığından genellikle karşı önerilir. Default_scope'un iyi bir kullanımı, sonuç kümesini sıralamaktır.

whereDefault_scope kullanmaktan uzak durur ve bunun için bir kapsam oluştururum.


1
İkinci sorun "Kapsamı Kaldırılmamış, normalde seçtiğiniz için geçerli olabilecek TÜM kapsamları kaldırır, ilişkilendirmeler dahil (ancak bunlarla sınırlı değildir)", default_scopeyalnızca şunu içeriyor olsa bile hala mevcuttur order. Bu davranış unscopedoldukça beklenmedik bir durumdur.
Zack Xu

1

Benim için ise değil bir kötü bir fikir ama dikkatli kullanılması gerekir !. Bir alan ayarlandığında her zaman belirli kayıtları gizlemek istediğim bir durum vardır.

  1. Tercihen default_scopeDB varsayılan değerle aynı olmalıdır (örneğin: { where(hidden_id: nil) })
  2. Bu kayıtları göstermek istediğinizden tamamen emin olduğunuzda, her zaman unscopedsizden sakınacak bir yöntem vardır.default_scope

Yani bağlı olacak ve gerçek ihtiyaçlar.


0

Ben sadece , her durumda default_scopebazı parametreleri sıralamak ascveya sıralamak için faydalı buluyorum desc. Aksi takdirde veba gibi kaçınırım

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.