2012-03-15 4 views
10

저는 ActiveRecord :: Relation을 반환하는 다른 ActiveRecord 클래스 메서드보다 스코프의 이점을 찾으려는 10 페이지 이상을 조사했습니다. 예제에 대해 다음에서 스코프의 실제 이점은 무엇입니까

왜 같은 일을 그 아래에있는 대안보다 더 범위입니다

#scope :pat1, lambda {{:conditions => ["name like ?", 'J%']}}  
    #scope :pat2, lambda {{:conditions => ["id > 5"]}} 

    def self.pat1 
    where("name like ?", 'J%') 
    end 

    def self.pat2 
    where("id > 5") 
    end 

    def patx 
    self.class.pat1.pat2.first 
    end 

문서해서 또 다시 그들이 체인 될 수 있기 때문에 범위가 도움이되는 것을 말한다 ...

"모든 범위 메서드는 다른 메서드와 같은 다른 메서드를 호출 할 수있는 ActiveRecord :: Relation 개체를 반환합니다." - guides.rubyonrails.org

http://ruby.railstutorial.org

...하지만 대안은 위 또한 생산 체인 될 수있다 "주된 이유 범위는 일반 클래스의 방법보다 더 나은 그들이 다른 방법으로 체인 될 수 있다는 것입니다" 같은 결과.

여기에 황제의 새 옷이 있는지 알아 내려고합니다. 통사론적인 관점에서조차도 아무런 유익이없는 것으로 보인다. 그들은 더 빠릅니다 - 일부 소식통은 모호하게 그것을 제안합니다.

답변

3

ActiveRecord 범위는 이미 언급 한 것처럼 모범 사례로 포장 된 설탕 설탕입니다.

레일스의 2.x 일 동안 "named_scope"라고 불렸을 때, 그들은 조금 더 중요했습니다. 쿼리를 생성하기위한 조건을 쉽게 연결할 수있었습니다. 레일즈 3.x에서 Arel을 사용하여 개선 된 기능을 통해 쿼리 관계에 대한 함수를 만드는 것이 간단합니다. Scopes는 체인 가능하고 미리 정의 된 쿼리에 대해 간단하고 우아한 솔루션을 제공합니다. 모든 스코프를 모델의 맨 위에 올리면 가독성이 향상되고 모델 사용 방법이 표시됩니다.

+0

Arel 나는 ActiveRecord :: Relation을 의미한다고 가정합니다. 승인. 통사론적인 이점은 나에게 논쟁의 여지가있다. 그러나 그들이 표준 방법이 이전 버전에서 할 수없는 일을한다면 그것은 그것을 설명합니다. – Mark

+2

더 나은 구문을 사용하는 레일이 중요합니다. 1 일 (또는 심지어 100 일) 코드베이스가 아니라 1000 일 코드베이스입니다. –

2

예, 구문 기반 단축키는 사용자가 찾은 방법을 기본적으로 나타냅니다.
왜 더 좋습니까?
가장 즉각적인 효과는 2 줄 코드가 9 줄의 코드보다 읽고 유지하는 것이 더 쉽다는 것입니다.

레일즈는 항상 DRY 접근법을 추구합니다. 여기에서 반복되는 def self.method end은 실제 코드를 모호하게합니다.

+0

당신과 Sean Hill이 속도 문제가 아니라는 것을 확인해 주셔서 감사합니다. 위의 railstutorial.org 링크는 특히 범위를 사용하는 대체 구현이 다소 빠르지 만 스코프를 사용하는 것과 분명히 관련이 없다는 말을 시작합니다. – Mark

3

스코프를 쓸 때, 그것은 본질적으로 같은 일을합니다.

def scope(name, scope_options = {}) 
     name = name.to_sym 
     valid_scope_name?(name) 
     extension = Module.new(&Proc.new) if block_given? 

     scope_proc = lambda do |*args| 
     options = scope_options.respond_to?(:call) ? unscoped { scope_options.call(*args) } : scope_options 
     options = scoped.apply_finder_options(options) if options.is_a?(Hash) 

     relation = scoped.merge(options) 

     extension ? relation.extending(extension) : relation 
     end 

     singleton_class.send(:redefine_method, name, &scope_proc) 
    end 

이 경우 스코프 수있는 혜택들은 어떤 경우에는 적은 코드를 쿼리를 정의하는 관용적 인 방법입니다 것을, 그리고 당신이 확장 기능을 수행 할 수 있습니다 여기에 레일 소스가 모습입니다.

소스의 예는 다음과 같습니다 : 당신이 Model.red.dom_id를 호출 할 수 있습니다

scope :red, where(:color => 'red') do 
    def dom_id 
    'red_shirts' 
    end 
end 

합니다.

0

관계를 반환하는 범위와 클래스 메서드 간에는 몇 가지 매우 흥미로운 차이가 있습니다.

  1. PARAM이 전무 관계를 야기 경우 간단한 param.present? 검사와 범위에 대한 무기 호 매개 변수를 처리하기 쉽게하고, 클래스 메소드에 대해 명시 적으로 nil이 아닌 관계를 반환해야합니다.

  2. 범위는 클래스 메서드보다 쉽게 ​​확장 할 수 있습니다. 메소드를 추가하기 위해 블록을 전달하십시오 (예 : 페이지 매김을 처리하기 위해). 클래스 메소드는 확장 될 수 있지만 우아하게는 확장 될 수 없습니다.

전체 설명은 this post from Plataformatec을 참조하십시오.

관련 문제