Rails3, ActiveRecord를 사용하고 있습니다
AND가 아닌 OR 문으로 범위를 연결하는 방법이 궁금합니다.
예 :
Person.where(:name => "John").where(:lastname => "Smith")
일반적으로 다음을 반환합니다.
name = 'John' AND lastname = 'Smith'
그러나 나는 싶습니다 :
`name = 'John' OR lastname = 'Smith'
Rails3, ActiveRecord를 사용하고 있습니다
AND가 아닌 OR 문으로 범위를 연결하는 방법이 궁금합니다.
예 :
Person.where(:name => "John").where(:lastname => "Smith")
일반적으로 다음을 반환합니다.
name = 'John' AND lastname = 'Smith'
그러나 나는 싶습니다 :
`name = 'John' OR lastname = 'Smith'
답변:
당신은 할 것
Person.where('name=? OR lastname=?', 'John', 'Smith')
현재 새로운 AR3 구문에 의한 다른 OR 지원은 없습니다 (즉, 일부 타사 gem을 사용하지 않음).
.or
내장되어 있을 것 입니다 .
ARel 사용
t = Person.arel_table
results = Person.where(
t[:name].eq("John").
or(t[:lastname].eq("Smith"))
)
동일한 열 또는 쿼리에 대해 배열 구문을 게시하면 엿볼 수 있습니다.
Person.where(name: ["John", "Steve"])
Rails4 업데이트
타사 보석이 필요하지 않습니다
a = Person.where(name: "John") # or any scope
b = Person.where(lastname: "Smith") # or any scope
Person.where([a, b].map{|s| s.arel.constraints.reduce(:and) }.reduce(:or))\
.tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }
이전 답변
타사 보석이 필요하지 않습니다
Person.where(
Person.where(:name => "John").where(:lastname => "Smith")
.where_values.reduce(:or)
)
or
텍스트 블록 내의 보간 또는 다른 연산자가 필요 하며 OP 코드에는 반영되지 않습니다.
...where_values.join(' OR ')
내 경우
.tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }
스코프에 바인딩이 필요한 변수가없는 경우 부품을 생략 할 수 있습니다 .
MetaWhere gem을 사용 하여 코드를 SQL과 섞지 않을 수도 있습니다 .
Person.where((:name => "John") | (:lastname => "Smith"))
누구 든지이 답변에 대한 업데이트 된 답변을 찾고 있다면 Rails https://github.com/rails/rails/pull/9052 로 가져 오는 기존 풀 요청이있는 것처럼 보입니다 .
ActiveRecord ( https://gist.github.com/j-mcnally/250eaaceef234dd8971b )에 대한 @ j-mcnally의 원숭이 패치 덕분에 다음을 수행 할 수 있습니다.
Person.where(name: 'John').or.where(last_name: 'Smith').all
더 중요한 것은 다음과 OR
같이 범위를 연결할 수있는 기능입니다 .
scope :first_or_last_name, ->(name) { where(name: name.split(' ').first).or.where(last_name: name.split(' ').last) }
scope :parent_last_name, ->(name) { includes(:parents).where(last_name: name) }
그런 다음 이름 또는 성 또는 이름을 가진 부모를 가진 모든 사람을 찾을 수 있습니다
Person.first_or_last_name('John Smith').or.parent_last_name('Smith')
이것을 사용하는 가장 좋은 예는 아니지만 질문에 맞추려고합니다.
.or
체인 기능 릴리스를 목표로합니다 . Rails> = 3.2에서 언급 한 원숭이 패치를 사용할 수있었습니다. 그러나 Rails 5가 코드에 오랜 변화를 가져 오기를 기다릴 수 있습니다.
업데이트 된 Rails / ActiveRecord 버전은이 구문을 기본적으로 지원할 수 있습니다. 다음과 유사합니다.
Foo.where(foo: 'bar').or.where(bar: 'bar')
이 풀 요청에 명시된 바와 같이 https://github.com/rails/rails/pull/9052
지금은 단순히 다음을 고수하는 것이 좋습니다.
Foo.where('foo= ? OR bar= ?', 'bar', 'bar')
Foo.where(foo: 'bar1').or.where(bar: 'bar2')
작동하지 않습니다. Foo.where (foo : 'bar1'). or.where (Foo.where (bar : 'bar2'))
레일 4 + 스코프 + Arel
class Creature < ActiveRecord::Base
scope :is_good_pet, -> {
where(
arel_table[:is_cat].eq(true)
.or(arel_table[:is_dog].eq(true))
.or(arel_table[:eats_children].eq(false))
)
}
end
나는 .or와 운이없는 스코프라는 체인을 시도했지만 부울 세트가있는 것을 찾는 데 효과적이었습니다. 같은 SQL을 생성
SELECT 'CREATURES'.* FROM 'CREATURES' WHERE ((('CREATURES'.'is_cat' = 1 OR 'CREATURES'.'is_dog' = 1) OR 'CREATURES'.'eats_children' = 0))
전체 데이터 세트에서 명시 적으로 작업하는 대신 범위를 제공하려는 경우 Rails 5로 수행해야 할 작업은 다음과 같습니다.
scope :john_or_smith, -> { where(name: "John").or(where(lastname: "Smith")) }
또는:
def self.john_or_smith
where(name: "John").or(where(lastname: "Smith"))
end
"or"문을 포함하기 위해 where 절을 수동으로 작성할 수없는 경우 (즉, 두 범위를 결합하려는 경우) union을 사용할 수 있습니다.
Model.find_by_sql("#{Model.scope1.to_sql} UNION #{Model.scope2.to_sql}")
(출처 : ActiveRecord Query Union )
쿼리와 일치하는 모든 레코드를 반환합니다. 그러나 이것은 arel이 아닌 배열을 반환합니다. 아레를 실제로 반환하려면 https://gist.github.com/j-mcnally/250eaaceef234dd8971b 요점을 확인 하십시오 .
원숭이 패치 레일이 마음에 들지 않는 한이 작업이 수행됩니다.
다음 관련 질문도 참조하십시오 : here , here 및 here
Person
.unscoped # See the caution note below. Maybe you want default scope here, in which case just remove this line.
.where( # Begin a where clause
where(:name => "John").where(:lastname => "Smith") # join the scopes to be OR'd
.where_values # get an array of arel where clause conditions based on the chain thus far
.inject(:or) # inject the OR operator into the arels
# ^^ Inject may not work in Rails3. But this should work instead:
.joins(" OR ")
# ^^ Remember to only use .inject or .joins, not both
) # Resurface the arels inside the overarching query
주 말에 기사의주의 :
레일스 4.1+
Rails 4.1은 default_scope를 일반 범위처럼 취급합니다. 기본 범위 (있는 경우)는 where_values 결과에 포함되며 inject (: or)는 기본 범위와 위치 사이에 추가하거나 설명합니다. 그 나쁜.
이를 해결하려면 쿼리 범위를 지정하지 않아도됩니다.
squeel
보석이 작업을 수행 할 수있는 매우 쉬운 방법을 제공합니다 (전 @의 coloradoblue의 방법 등이 내가 사용하는 뭔가) :
names = ["Kroger", "Walmart", "Target", "Aldi"]
matching_stores = Grocery.where{name.like_any(names)}
따라서 원래 질문에 대한 대답은 'and'대신 'or'로 범위에 참여할 수 있습니까? 그러나 작업을 수행하는 완전히 다른 범위 나 쿼리를 직접 코딩하거나 MetaRecord 또는 Squeel과 같은 ActiveRecord와 다른 프레임 워크를 사용할 수 있습니다. 내 경우에는 유용하지 않다
pg_search에 의해 생성 된 범위를 '또는'선택하고 있습니다. 선택보다 약간 더 많은 것을 포함합니다 .ASC에 의한 순서가 포함되어있어 깨끗한 노동 조합을 혼란스럽게 만듭니다. pg_search에서 할 수없는 일을하는 손수 만든 범위로 '또는'하고 싶습니다. 그래서 나는 이것을 이렇게해야했습니다.
Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")
즉, 범위를 sql로 바꾸고 각 괄호를 묶고 함께 결합 한 다음 생성 된 sql을 사용하여 find_by_sql을 찾으십시오. 약간 쓰레기이지만 작동합니다.
아니요, pg_search에서 "against : [: name, : code]"를 사용할 수 있다고 말하지 마십시오. 그렇게하고 싶지만 'name'필드는 hstore이며 pg_search는 처리 할 수 없습니다 아직. 따라서 이름으로 범위를 직접 만든 다음 pg_search 범위와 통합해야합니다.