빈 ActiveRecord 관계를 반환하는 방법?


246

람다가있는 스코프가 있고 인수의 값에 따라 인수가 필요한 경우 일치하는 항목이 없다는 것을 알고 있지만 빈 배열이 아닌 관계를 반환하려고합니다.

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }

내가 정말로 원하는 것은 "모두"의 반대 인 "없음"방법으로, 여전히 연결될 수있는 관계를 반환하지만 쿼리는 단락됩니다.


쿼리를 허용하면 User.where ( 'id in (?)', []). class => ActiveRecord :: Relation 관계를 반환합니다. 쿼리를 완전히 피하려고합니까?
Brian Deterling

1
옳은. 일치하는 항목이 없을 경우 이상적으로는 쿼리를 완전히 피할 수 있습니다. 나는 이것을 간단히 ActiveRecord :: Base : "def self.none; where (: id => 0); end"에 추가했습니다.
dzajic

1
> 쿼리를 완전히 피하려고합니까? 전적으로 이해가 될 것입니다. 우리가 DB를 치기 위해 필요한 절름발이
dolzenko

답변:


478

Rails 4에는 "올바른"메커니즘이 있습니다.

>> Model.none 
=> #<ActiveRecord::Relation []>

14
지금까지 이것은 3.2 이하로 포팅되지 않았습니다. 유일한 가장자리 (4.0)
크리스 블룸


2
Rails 4.0.5로 시도해 보았습니다. 이 기능은 Rails 4.0 릴리스에 적용되었습니다.
진화

3
@AugustinRiedinger은 Model.scoped무엇을 당신이 찾고있는 것은 3 레일 않습니다
팀 Diggins

9
Rails 4.0.5부터는 Model.none작동하지 않습니다. 실제 모델 이름 중 하나를 사용해야 User.none합니다.
Grant Birchmeier

77

"id"열을 필요로하지 않고 id가 0 인 행이 없다고 가정하지 않는보다 편리한 솔루션 :

scope :none, where("1 = 0")

나는 아직도 더 "올바른"방법을 찾고 있습니다.


3
네,이 답변이 우리에게 최고라고 생각합니다. ActiveRecord / Arel은 여전히 ​​미성숙해야합니다. 루비에서 빈 배열을 만들기 위해 perambulations를 거쳐야한다면 정말 짜증납니다. 기본적으로 여기도 마찬가지입니다.
Purplejacket

다소 hackish 있지만, 이것은 이다 레일 3.2에 대한 올바른 방법. Rails 4의 경우 @ steveh7의 다른 답변을 참조하십시오 : stackoverflow.com/a/10001043/307308
scarver2

scope :none, -> { where("false") }
0 분 54 초

43

레일스 4에 오는

Rails 4 ActiveRecord::NullRelation에서와 같은 호출에서 체인 가능 항목 이 반환됩니다 Post.none.

그것도 체인 메소드도 데이터베이스에 쿼리를 생성하지 않습니다.

의견에 따르면 :

반환 된 ActiveRecord :: NullRelation은 Relation에서 상속되며 Null Object 패턴을 구현합니다. null 동작이 정의 된 객체이며 데이터베이스를 quering하지 않고 항상 빈 레코드 배열을 반환합니다.

소스 코드를 참조하십시오 .


42

"없음"이라는 범위를 추가 할 수 있습니다.

scope :none, where(:id => nil).where("id IS NOT ?", nil)

그러면 빈 ActiveRecord :: Relation이 제공됩니다.

이니셜 라이저의 ActiveRecord :: Base에 추가 할 수도 있습니다 (원하는 경우).

class ActiveRecord::Base
 def self.none
   where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
 end
end

이와 같은 것을 얻을 수있는 많은 방법이 있지만 코드베이스에 보관하는 것이 가장 좋은 방법은 아닙니다. 리팩토링하고 빈 ActiveRecord :: Relation을 단기간 동안 보장해야한다는 것을 알 때 범위를 사용하지 않았습니다.


14
where('1=2')좀 더 간결 할 수도 있습니다
Marcin Raczkowski

10
새로운 '올바른'답변으로 스크롤을 내리지 않으면 : Model.none어떻게해야합니까?
Joe Essey

26
scope :none, limit(0)

범위가 연결되어 있기 때문에 위험한 솔루션입니다.

User.none.first

첫 번째 사용자를 반환합니다. 사용하는 것이 더 안전합니다

scope :none, where('1 = 0')

2
이것은 올바른 'scope : none, where ('1 = 0 ')'입니다. 페이지 매김이 있으면 다른 하나는 실패합니다
Federico

14

다른 옵션을 보는 방식을 선호한다고 생각합니다.

scope :none, limit(0)

다음과 같은 결과로 이어집니다.

scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }

나는 이것을 선호합니다. 왜 where(false)일을하지 않을지 잘 모르겠습니다 . 범위가 변경되지 않습니다.
aceofspades

4
그주의 limit(0)전화 할 경우 무시됩니다 .first또는 .last레일을 추가하기 때문에, 체인 나중에 LIMIT 1해당 쿼리에.
zykadelic

2
@aceofspades where (false)는 작동하지 않지만 (Rails 3.0) where ( 'false')는 작동합니다. 당신은 아마 지금 2013 년 걱정하지 않습니다 :)
Ritchie

@Ritchie에게 감사드립니다. 그 이후로 우리는 none아래에 언급 된 것처럼 관계 가 있다고 생각 합니다.
aceofspades

3

범위가 지정된 사용 :

scope : for_users, 람다 {| users | users.any? ? where ( "user_id IN (?)", users.map (& : id) .join ( ',')) : scoped}

그러나 다음을 사용하여 코드를 단순화 할 수도 있습니다.

scope : for_users, 람다 {| users | users.any 인 경우 where (: user_id => users.map (& : id))? }

빈 결과를 원하면 이것을 사용하십시오 (if 조건을 제거하십시오).

scope : for_users, 람다 {| users | where (: user_id => users.map (& : id))}

"범위"또는 nil을 반환해도 원하는 결과를 얻지 못하므로 결과를 0으로 제한합니다. "scoped"또는 nil을 반환해도 범위에는 영향을 미치지 않습니다 (일부 경우에는 유용하지만 내 경우는 아님). 나는 내 자신의 대답을 생각해 냈습니다 (위의 의견 참조).
dzajic

빈 결과를 반환하는 간단한 솔루션을 추가했습니다. :)
Pan Thomakos


1

변형이 있지만 모두 db에 요청합니다.

where('false')
where('null')

2
BTW 문자열이어야합니다. where(false)또는 where(nil)단순히 무시됩니다.
mahemoff
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.