Rails default_scope 재정의


155

기본 범위를 가진 ActiveRecord :: Base 모델이있는 경우 :

class Foo < ActiveRecord::Base

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

end

조건 Foo.find 사용 하지 않고 할 수있는 방법이 default_scope있습니까? 즉, 기본 범위를 재정의 할 수 있습니까?

이름에 'default'를 사용하면 재정의 가 가능 하다는 것을 암시한다고 생각 했을 것입니다 global_scope.


답변:


151

짧은 대답 : 꼭 필요한 경우가 default_scope아니면 사용 하지 마십시오 . 명명 된 범위를 사용하는 것이 좋습니다. 그렇게 말하면 with_exclusive_scope필요한 경우 기본 범위를 재정의하는 데 사용할 수 있습니다.

자세한 내용 은 이 질문 을 보십시오 .


이전 질문에 대한 링크 감사합니다
Gareth

10
> 실제로 필요한 경우가 아니면 default_scope를 사용하지 마십시오. 훌륭한 조언! 감사합니다!
installero

2
그렇습니다. 사용 default_scope하는 것이 좋은 생각처럼 보이지만 앱 수명 동안 여러 번 두통을 일으킬 수 있습니다.
thomax


1
당신은 작은 선생님을 과장하고 있습니다. default_scope훌륭한 도구이며 다른 방법으로 할 수는 있지만 default_scope올바른 일을 할 수있는 상황이 있습니다 . 예를 들어 플래그 가있는 Product모델이있는 경우 99 % 또는 비활성 제품을 표시하지 않으려는 경우 inactivea를 설정하는 default_scope { where inactive: false }것이 가장 좋습니다. 그런 다음 unscoped나머지 1 % 사례를 호출하면 아마도 관리자 패널 일 것입니다.
pedrozath

215

레일즈 3에서 :

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

58
Post has_many Comment, Post.first.comments.unscoped가 모든 주석을 반환하면 부작용이 있습니다.
Enrico Carlesso

3
이것은 정말로 나를 잠시 망쳤다. 특히 이것을 다음과 같은 클래스 메소드에 넣으면 : def self.random; unscoped.order('rand()'); endunscoped는 default_scope에 나열된 것뿐만 아니라 모든 SQL을 제거합니다. 기술적으로 정답이지만 다음을 사용하여주의하십시오.unstopped
Schneems

7
경고! Unscoped는 default_scope 만 제거하지 않고 이미 다른 의견에서 언급되었지만 실제로는 문제가 발생할 수 있습니다.
dsimard

15
엄지 손가락의 좋은 규칙은이다 unscoped가 직접 모델을 따를 수 있습니다 때, 예를 들면 Foo.unscoped.blah()하지만 결코 괜찮습니다 Foo.blah().unscoped.
Grant Birchmeier

stackoverflow.com/questions/1834159/… Enrico가 언급 한 부작용에 대해 작동
wbharding

107

에 정의 된 순서를 변경하기 만하면 메소드를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

3
팁 : 범위를 정의 scope :without_default_order, -> { reorder("") }하고 다음 과 같은 작업을 수행 할 수 있습니다 Foo.without_default_order.order("created_at ASC"). 일부 상황에서는 더 잘 읽습니다 (이 정확한 상황은 아니지만 나름대로).
Henrik N

재정렬은 나를 위해 그것을했다. 고마워요!
Andre Zimpel

49

때문에 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 . 그것은 당신 자신의 이익을위한 것입니다.


이 답변은 높아야한다
스티븐 코윈


5

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를 제거하고 명시 적으로 모든 곳에서 코딩하고 있습니다.

함정 레일 3!


1
당신은 사용해야합니다Bar.foos.reorder(:created_at => :asc)
Ivan Stana

5

Rails 3 이상에서는 범위가 지정되지 않고 병합 된 조합을 사용할 수 있습니다.

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

이것은 또한 unscoped를 먼저 호출하기 위해 나를 위해 일했습니다 (Rails 4.2) :User.unscoped.where(email: "foo@example.com")
Nick

3

On Rails 5.1 이상에서는 (그리고 이전에는 테스트했지만 5.1에서 작동했습니다) 특정 열의 범위를 좁힐 수 있습니다 .imho default_scope는 명명 된 범위 내에서 사용할 수있는 방식으로 를 제거하기위한 이상적인 솔루션입니다 . OPS의 경우 default_scope,

Foo.unscope(where: :bar)

또는

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

둘 다 원래 범위를 적용하지 않지만 다른 조건이 영역으로 병합되는 모든 것을 적용하는 SQL 쿼리를 생성합니다.


2

글쎄, 당신은 항상 find_by_sql완전한 쿼리와 함께 옛날 즐겨 찾기 를 사용할 수 있습니다. 예를 들면 다음과 같습니다. Model.find_by_sql ( "SELECT * FROM models WHERE id = 123")

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