rails default_scope를 자주 사용하는 이유는 무엇입니까?


126

도처 인터넷 사람들은 레일을 사용하여 언급 나쁜 생각이며,의 최고 히트 유래에 그것을 덮어 쓰기하는 방법에 대해입니다. 이것은 엉망인 느낌이 들며 명시적인 질문을 할 가치가 있습니다 (제 생각에).default_scopedefault_scope

그렇다면 default_scope권장 되는 레일을 사용하는 이유는 무엇입니까?

답변:


192

문제 1

기본적인 예를 살펴 보겠습니다.

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

default를 설정하려는 동기 published: true는 게시되지 않은 (비공개) 게시물을 표시하고 싶을 때 명시해야 할 수 있습니다. 여태까지는 그런대로 잘됐다.

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

이것은 우리가 기대하는 것입니다. 이제 시도해 보겠습니다.

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

그리고 여기에 기본 범위에 대한 첫 번째 큰 문제가 있습니다.

=> default_scope는 모델 초기화에 영향을 미칩니다.

이러한 모델의 새로 생성 된 인스턴스 default_scope에서이 반영됩니다. 따라서 게시되지 않은 게시물을 우연히 나열하지 않기를 원했지만 이제는 기본적으로 게시 된 게시물을 만들고 있습니다.

문제 2

보다 정교한 예를 고려하십시오.

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

class User < ActiveRecord::Base
  has_many :posts
end

첫 번째 사용자 게시물을 얻을 수 있습니다.

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]]

예상 한 것처럼 보입니다 (user_id에 대한 부분을 보려면 오른쪽 끝까지 스크롤해야합니다).

이제 로그인 한 사용자의보기에 대해 게시되지 않은 모든 게시물의 목록을 가져 오려고합니다. 의 효과를 '덮어 쓰거나' '실행 취소'해야한다는 것을 알게 될 것입니다 default_scope. 간단한 Google 검색을 마치면 unscoped. 다음에 무슨 일이 일어나는지 확인하십시오.

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

=> Unscoped는 연결을 포함하여 (그러나 이에 국한되지는 않음) 선택 항목에 일반적으로 적용될 수있는 모든 범위를 제거합니다.

의 다양한 효과를 덮어 쓰는 방법에는 여러 가지가 있습니다 default_scope. 그 권리를 얻는 것은 매우 빠르게 복잡해 지며 default_scope처음에를 사용하지 않는 것이 더 안전한 선택이 될 것이라고 주장 합니다.


2
쌓아두기 위해 : default_scope가 유용하다고 생각한 유일한 시간은 기본적으로 일부 연결을 절대적으로로드하려는 경우입니다. default_scope {eager_load ([: category, : comments])}. 하나!!! Product.count와 같은이 모델에 대해 카운트 쿼리를 수행하는 경우 모든 제품에 대한 eager_load 연결이 수행됩니다. 그리고 50K 레코드가있는 경우 카운트 쿼리가 15ms에서 500ms로 변경되었습니다. 원하는 것은 카운트이지만 default_scope는 다른 모든 항목을 조인합니다.
konung

16
나에게 그 문제로 보인다 unscoped대신 default_scope이 문제 #에서
캡틴 Fogetti

4
@CaptainFogetti 맞아요. 나는 여전히 default_scope의 가능한 단점으로 unscoped의 단점을 제시하는 것이 좋은 생각이라고 생각합니다. 대부분의 사소하지 않은 경우 default_scope를 사용하면 unscoped를 사용해야합니다. 이것은 2 단계주의 사항 (더 나은 용어가 없음)이며 방법을 연구 할 때 놓치기 쉽습니다.
wrtsprt

1
답변의 유스 케이스의 문제점은 게시되지 않은 게시물을 찾고 싶은 경우가 많다는 것입니다. 사실 게시 된 게시물을 찾는 것은 특별한 경우라고 주장합니다. 게시 된 게시물을 원하는 유일한 시간은 누군가가 공개 페이지를 볼 때입니다. 그러나 게시되지 않은 게시물을보고 싶을 때가 많습니다.
B Seven

3
나는 default_scope당신이 무언가를 분류하고 싶을 때 의 좋은 사용이라고 생각합니다 : default_scope { order(:name) }.
user2985898

9

사용하지 않는 또 다른 이유 default_scope는 모델과 일대 다 관계가있는 default_scope모델 의 인스턴스를 삭제할 때입니다.

예를 들어 :

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

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

를 호출 user.destroy하면 인 게시물이 모두 삭제 published되지만 인 게시물은 삭제 되지 않습니다 unpublished. 따라서 데이터베이스에는 제거하려는 사용자를 참조하는 레코드가 포함되어 있으므로 외래 키 위반이 발생합니다.


6

default_scope는 종종 결과 집합을 제한하는 데 잘못 사용되기 때문에 권장되지 않습니다. default_scope의 좋은 사용은 결과 집합을 정렬하는 것입니다.

나는 wheredefault_scope 에서 사용 하지 않고 오히려 그 범위를 만들 것입니다.


1
두 번째 문제 "범위가 지정되지 않음은 연결을 포함하여 (이에 국한되지 않음) 선택에 일반적으로 적용 할 수있는 모든 범위를 제거합니다"라는 문제는에 default_scope만 포함되어 있어도 여전히 존재합니다 order. 의이 동작은 unscoped예상치 못한 것입니다.
Zack Xu

1

나를 위해입니다 하지 나쁜 생각 하지만주의해서 사용해야합니다! 필드를 설정할 때 항상 특정 레코드를 숨기고 싶었던 경우가 있습니다.

  1. 가급적 default_scopeDB 기본값과 일치해야합니다 (예 :{ where(hidden_id: nil) } )
  2. 이러한 기록을 보여주고 싶다는 확신이 들면 항상 unscoped귀하의 기록 을 피할 수 있는 방법이 있습니다.default_scope

따라서 그것은 실제 필요에 달려 있습니다.


0

난 단지 찾을 default_scope에서만 할 몇 가지 매개 변수를 주문에 유용하게 asc또는 desc모든 상황에서 순서. 그렇지 않으면 전염병처럼 피합니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.