복붙노트

[RUBY-ON-RAILS] OR (대신 AND)와 함께 두 개의 명명 범위를 결합

RUBY-ON-RAILS

OR (대신 AND)와 함께 두 개의 명명 범위를 결합

나는 그의 몸 중 모든 주석을 찾으려면 :

이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

SearchLogic 당신이 다음의 각을 수행 할 수 있지만 나는 가능하면 SearchLogic를 사용하려면,하지만 것입니다 :

그리고 당신은 항상 그들을 함께 체인 수 있습니다. Annotation.body_equals ( '?') body_like ( '[?])

나는 OR와 조합하는 방법을 모르겠어요.

그들의 인수가 동일한 경우 OR로 이름 범위를 결합 할 수 있습니다. 예를 들어, 내가 할 수있는 :

 Annotation.body_equals_or_body_like('?')

그러나이 도움이되지 것입니다.

내가 SearchLogic에 부착 아니지만, 그것의 추상화를 깨는 필요로하지 않는 솔루션에 대한 좋은 것입니다 있습니다.

해결법

  1. ==============================

    1.나는 어떤 간단한 해결책을 찾을 수 없습니다,하지만 난 내 자신의 솔루션을 압연 있도록이 문제는 나에게 흥미 :

    나는 어떤 간단한 해결책을 찾을 수 없습니다,하지만 난 내 자신의 솔루션을 압연 있도록이 문제는 나에게 흥미 :

    class ActiveRecord::Base
    
      def self.or_scopes(*scopes)
        # Cleanup input
        scopes.map! do |scope|
          scope = scope.respond_to?(:to_a) ? scope.to_a : [*scope]
          scope.unshift(scope.shift.to_sym)
        end
    
        # Check for existence of scopes
        scopes.each{|scope| raise ArgumentError, "invalid scope: #{scope.first}" unless self.scopes.has_key?(scope.first) }
    
        conditions = scopes.map do |scope|
          scope = self.scopes[scope.first].call(self, *scope[1..-1])
          self.merge_conditions(scope.proxy_options[:conditions])
        end
    
        or_conditions = conditions.compact.join(" OR ")
    
        merged_scopes = scopes.inject(self){|merged, scope| merged.scopes[scope.first].call(self, *scope[1..-1]) }
    
        # We ignore other scope types but so does named_scopes
        find_options = merged_scopes.scope(:find).merge(:conditions => or_conditions)
    
        self.scoped(find_options)
      end
    
    end
    

    다음 설치를 고려하십시오

    class Person < ActiveRecord::Base
      named_scope :men,      :conditions => { :sex => 'M' }
      named_scope :women,    :conditions => { :sex => 'F' }
      named_scope :children, :conditions => "age < 18"
      named_scope :named, lambda{|name|
        { :conditions => { :name => name } }
      }
    end
    

    당신은 같은 범위의 일련의 이름과 전화 :

    Person.or_scopes(:women, :children)
    

    이 같은 범위를 반환합니다 :

    Person.or_scopes(:women, :children).proxy_options
    # => {:conditions=>"(`people`.`sex` = 'F') OR (age < 18)"}
    

    범위가 매개 변수를 필요로 할 때 당신은 또한 배열의 배열로 호출 할 수 있습니다 :

    Person.or_scopes(:women, [:named, 'Sue']).proxy_options
    # => {:conditions=>"(`people`.`sex` = 'F') OR (`people`.`name` = 'Sue')"}
    

    귀하의 경우 호레이스, 당신은 다음을 사용할 수 있습니다 :

    Annotation.or_scopes([:body_equals, '?'], [:body_like, '[?']).all
    
  2. ==============================

    2.'와 같은'는 결과도 '등호'결과를 포함하지 않을까요?

    '와 같은'는 결과도 '등호'결과를 포함하지 않을까요?

    또한 정말로 긴 이름 범위를 만들기 위해 다른 사람의 말에 명명 된 범위를 사용할 수 있습니다. Searchlogic 문서 도구에서 (이 방법은 나에게 longwinded 조금 보인다)

    User.username_or_first_name_like("ben")
    => "username LIKE '%ben%' OR first_name like'%ben%'"
    
    User.id_or_age_lt_or_username_or_first_name_begins_with(10)
    => "id < 10 OR age < 10 OR username LIKE 'ben%' OR first_name like'ben%'"
    

    아니면 중복을 제거하는 동안 검색 결과 배열을 결합하는 노동 조합을 사용할 수 있습니다 :

    @equal_results = Annotation.body_equals('?')
    @like_results  = Annotation.body_like('[?]')
    @results = @equal_results | @like_results
    
  3. ==============================

    3.레일 2.x를 들어, 시뮬레이션 또는 다음 명명 된 범위를 사용할 수 있습니다 :

    레일 2.x를 들어, 시뮬레이션 또는 다음 명명 된 범위를 사용할 수 있습니다 :

        __or_fn = lambda do |*scopes|
        where = []
        joins = []
        includes = []
    
        # for some reason, flatten is actually executing the scope
        scopes = scopes[0] if scopes.size == 1
        scopes.each do |s|
          s = s.proxy_options
          begin
            where << merge_conditions(s[:conditions])
          rescue NoMethodError
            where << scopes[0].first.class.merge_conditions(s[:conditions])
          end
          joins << s[:joins] unless s[:joins].nil?
          includes << s[:include] unless s[:include].nil?
        end
        scoped = self
        scoped = scoped.includes(includes.uniq.flatten) unless includes.blank?
        scoped = scoped.joins(joins.uniq.flatten) unless joins.blank?
        scoped.where(where.join(" OR "))
      end
      named_scope :or, __or_fn
    

    하자가 위의 예를 사용하여이 기능을 사용합니다.

    q1 = Annotation.body_equals('?')
    q2 = Annotation.body_like('[?]')
    Annotation.or(q1,q2)
    

    위의 코드는 하나의 쿼리를 실행합니다. 분기와 2 분기 쿼리의 결과를 보유하지 않는, 오히려 자신의 클래스는 액티브 :: NamedScope이다 :: 범위.

    또는 named_scope는 이러한 쿼리를 결합하고, OR와 조건을 결합한다.

    당신 수 또한 둥지 관찰 보고서,이 인위적인 예처럼 :

    rabbits = Animal.rabbits
    #<Animal id: 1 ...>
    puppies = Animal.puppies
    #<Animal id: 2 ...>
    snakes = Animal.snakes
    #<Animal id: 3 ...>
    lizards = Animal.lizards
    #<Animal id: 4 ...>
    
    Animal.or(rabbits, puppies)
    [#<Animal id: 1 ...>, #<Animal id: 2 ...>]
    Animal.or(rabbits, puppies, snakes)
    [#<Animal id: 1 ...>, #<Animal id: 2 ...>, #<Animal id: 3 ...>]
    

    때문에 또는 리턴한다 액티브 :: NamedScope :: 범위 자체가, 우리가 정말 미친 갈 수 있습니다 :

    # now let's get crazy
    or1 = Animal.or(rabbits, puppies)
    or2 = Animal.or(snakes, lizards)
    Animal.or(or1, or2)
    [#<Animal id: 1 ...>, #<Animal id: 2 ...>, #<Animal id: 3 ...>, #<Animal id: 4...>]
    

    나는 시도하지 않은 있지만,이 예제의 대부분은, 레일 3의 범위를 사용하여 잘 작동한다고 생각합니다.

    뻔뻔한 자기 홍보의 비트 -이 기능은 fake_arel 보석에서 사용할 수 있습니다.

  4. ==============================

    4.나는 나에게 너무 복잡 보았다 "또는"두 named_scopes 모든 답변에 대한 답을 찾고이 질문을 온. 나는 조금을 조사하고 트릭을 수행 추가적인라고 named_scope "또는"을 사용하여 솔루션을 발견했다.

    나는 나에게 너무 복잡 보았다 "또는"두 named_scopes 모든 답변에 대한 답을 찾고이 질문을 온. 나는 조금을 조사하고 트릭을 수행 추가적인라고 named_scope "또는"을 사용하여 솔루션을 발견했다.

    주어진 예를 들면 다음과 같습니다

    Annotation.body_equals('?')
    Annotation.body_like('[?]')
    

    두 구조의 선택은 주석 레코드를 반환하는 named_scope 개체를 반환

    지금 우리는 같은 매개 변수로 두 개의 명명 범위를 기대하고 또 다른 이름 범위를 정의 :

    named_scope :or, lambda { |l, r| {
      :conditions => 
          "annotations.id IN (#{l.send(:construct_finder_sql,{:select => :id})}) or " + 
          "annotations.id IN (#{r.send(:construct_finder_sql,{:select => :id})})" 
    }}
    

    그런 다음 사용할 수 있습니다 :

    Annotation.or(Annotation.body_equals('?'), Annotation.body_like('[?]'))
    

    이 같은 쿼리를 작성합니다 :

    select * from annotations 
    where (annotations.id IN (select id from annotations where body='?') or
          (annotations.id IN (select id from annotations where body like '%?%')
    

    당신이 후에 무엇인지 어느

    또는도 named_scope, 그것은 또 다른 또는 기타 포함 named_scopes 체인 가능하다 :

    Annotation.or(Annotation.or(Annotation.body_equals('?'), 
                                Annotation.body_like('[?]')),
                  Annotation.some_other)
    
  5. ==============================

    5.아마도 그건

    아마도 그건

    Annotation.body_equals_or_body_like(['?', '[?]'])
    
  6. from https://stackoverflow.com/questions/1482940/combine-two-named-scopes-with-or-instead-of-and by cc-by-sa and MIT license