복붙노트

[RUBY-ON-RAILS] 어떻게 레일의 연결 방법의 일을?

RUBY-ON-RAILS

어떻게 레일의 연결 방법의 일을?

어떻게 레일의 연결 방법의 일을? 이 예제를 고려하자

class User < ActiveRecord::Base
   has_many :articles
end

class Article < ActiveRecord::Base
   belongs_to :user
end

이제 내가 좋아하는 뭔가를 할 수

@user = User.find(:first)
@user.articles

이것은 해당 사용자에 속하는 저 기사를 가져옵니다. 여태까지는 그런대로 잘됐다.

이제 더 나는 가서 몇 가지 조건이 기사에 발견 할 수 있습니다.

@user.articles.find(:all, :conditions => {:sector_id => 3})

또는 단순히 선언 및 협회 방법 등

class User < ActiveRecord::Base
   has_many :articles do
     def of_sector(sector_id)
       find(:all, :conditions => {:sector_id => sector_id})
     end
   end
end

그리고 이렇게

@user.articles.of_sector(3)

이제 내 질문입니다, 액티브 오브젝트의 배열이 찾기 작업이 연결 방법을 사용하여 가져 않는 방법? 우리는 우리 자신의 사용자 인스턴스 메소드라는 기사를 구현하고 있음은 협회의 방법을, 액티브의 인출 어레이의 발견 못해 작업을 객체로 우리에게 동일한 결과를 얻을 수 있습니다 우리 자신의 구현을 작성하는 경우 때문에.

내 생각 엔 협회의 방법을 발견하고 다른 액티브 방법을 사용하여 추가 질의를 가능하게 가져온 객체의 배열에 특정 속성을 첨부 할 것입니다. 이 코드 실행의 순서는이 경우 무엇입니까? 이걸 어떻게 확인할 수 있을까?

해결법

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

    1.어떻게 실제로 작동하는 것은 협회의 객체가 "프록시 객체"는 것이다. 특정 클래스는 AssociationProxy입니다. 해당 파일의 라인 (52)을 보면, 당신은 볼 수 있습니다 :

    어떻게 실제로 작동하는 것은 협회의 객체가 "프록시 객체"는 것이다. 특정 클래스는 AssociationProxy입니다. 해당 파일의 라인 (52)을 보면, 당신은 볼 수 있습니다 :

    instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
    

    이렇게함으로써, 클래스와 같은 방법은 더 이상이 개체에 존재하지 않습니다. 이 객체 클래스를 호출한다면, 당신은 방법이없는거야. 그래서, 거기 전달 프록시 오브젝트은 "대상"에 대한 메서드 호출을 위해 구현 된 method_missing :

    def method_missing(method, *args)
      if load_target
        unless @target.respond_to?(method)
          message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}"
          raise NoMethodError, message
        end
    
        if block_given?
          @target.send(method, *args)  { |*block_args| yield(*block_args) }
        else
          @target.send(method, *args)
        end
      end
    end
    

    대상은이 개체의 클래스를 호출 할 때, 그것은 배열 말한다, 배열이지만, 대상이 실제 클래스가 AssociationProxy이며, 배열 단지 때문이다,하지만 당신은 더 이상 그것을 볼 수 없습니다.

    그들이 직접 전화를받을 수 있도록 그래서 같은 of_sector로 추가하는 모든 방법은, 협회 프록시에 추가됩니다. 이들이 배열 된 목표로 전송받을 수 있도록 []와 같은 수준의 방법은, 연관 프록시에서 정의되지 않는다.

    도움말을 당신은 이런 일이 어떻게 association_proxy.rb의 로컬 복사본에서 해당 파일의 라인 (217)이 추가 참조 :

    Rails.logger.info "AssociationProxy forwarding call to `#{method.to_s}' method to \"#{@target}\":#{@target.class.to_s}" 
    

    그 파일이 어디 있는지 모르는 경우, 명령 보석은 'active_record / 협회 / association_proxy'당신을 말할 것이다. 당신이 AssociationProxy에 클래스를 호출 할 때 지금, 당신은 로그 메시지는 무슨 일이 일어나고 있는지가 명확하게해야 할 대상, 해당를 보내는을 알려주는 표시됩니다. 이 레일 2.3.2에 대한 모든이며 다른 버전에서 변경 될 수 있습니다.

  2. ==============================

    2.이미 언급 한 바와 같이, 활성 레코드 협회 편리한 메소드의 메트릭 buttload을 만들 수 있습니다. 물론, 당신은 모든 것을 가져 오기 위해 자신 만의 방법을 쓸 수 있습니다. 하지만 그 레일 웨이 없습니다.

    이미 언급 한 바와 같이, 활성 레코드 협회 편리한 메소드의 메트릭 buttload을 만들 수 있습니다. 물론, 당신은 모든 것을 가져 오기 위해 자신 만의 방법을 쓸 수 있습니다. 하지만 그 레일 웨이 없습니다.

    레일 웨이는 두 개의 모토의 절정이다. DRY (자신을 반복하지 않는 것) "구성을 통해 협약". 기본적으로 적합한 방식으로 사물을 명명하여, 프레임 워크를 할 수있는 모든 밖으로 추상적 인 공통의 코드에서 제공하는 몇 가지 강력한 방법. 당신이 당신의 질문에 배치 코드는 하나의 메소드 호출에 의해 대체 될 수있는 무언가의 완벽한 예입니다.

    이러한 편리한 방법이 정말 빛나는 어디 더 복잡한 상황이다. 관련된 일의 종류 등 모델, 조건, 검증에 가입

    (: 모두 : 조건 => [ "? created_at>"화요일])는 @ user.articles.find 같은 것을 할 때 귀하의 질문에 대답하기 위해, 레일은 두 개의 SQL 쿼리를 준비를하고 하나로 병합합니다. 어디 버전은 단지 객체의 목록을 반환한다. 명명 된 범위는 같은 일을하지만, 일반적으로 크로스 모델의 경계를하지.

    당신은 당신이 콘솔에서이 일을 전화로 development.log 파일에 SQL 쿼리를 확인하여 유효성을 검사 할 수 있습니다.

    그래서 그들은 SQL 핸들 레일 방법의 좋은 예를 제공하기 때문에 잠시 명명 된 범위에 대한 이야기를 할 수 있습니다, 그들은 어떤 모델 연결을 필요로하지 않는 한 나는 그들이 뒤에서 무슨 일이 일어나고 있는지 입증하는 간단한 방법이라고 생각 보여.

    명명 스코프는 모델의 사용자 정의 검색을 수행 할 수 있습니다. 그들은 서로 연결 또는 협회를 통해 호출 할 수 있습니다. 당신은 쉽게 동일한 목록을 반환 사용자 정의 측정기를 만들 수 있습니다,하지만 당신은 질문에서 언급 한 같은 문제로 실행합니다.

    class Article < ActiveRecord::Base
      belongs_to :user
      has_many :comments
      has_many :commentators, :through :comments, :class_name => "user"
      named_scope :edited_scope, :conditions => {:edited => true}
      named_scope :recent_scope, lambda do
        { :conditions => ["updated_at > ? ", DateTime.now - 7.days]}
    
      def self.edited_method
        self.find(:all, :conditions => {:edited => true})
      end
    
      def self.recent_method
        self.find(:all, :conditions => ["updated_at > ?", DateTime.now - 7 days])
      end
    end
    
    Article.edited_scope
    =>     # Array of articles that have been flagged as edited. 1 SQL query.
    Article.edited_method
    =>     # Array of Articles that have been flagged as edited. 1 SQL query.
    Array.edited_scope == Array.edited_method
    => true     # return identical lists.
    
    Article.recent_scope
    =>     # Array of articles that have been updated in the past 7 days.
       1 SQL query.
    Article.recent_method
    =>     # Array of Articles that have been updated in the past 7 days.
       1 SQL query.
    Array.recent_scope == Array.recent_method
    => true     # return identical lists.
    

    상황이 변경 곳은 다음과 같습니다

    Article.edited_scope.recent_scope
    =>     # Array of articles that have both been edited and updated 
        in the past 7 days. 1 SQL query.
    Article.edited_method.recent_method 
    => # no method error recent_scope on Array
    
    # Can't even mix and match.
    Article.edited_scope.recent_method
    =>     # no method error
    Article.recent_method.edited_scope
    =>     # no method error
    
    # works even across associations.
    @user.articles.edited.comments
    =>     # Array of comments belonging to Articles that are flagged as 
      edited and belong to @user. 1 SQL query. 
    

    본질적으로 명명 된 각 범위는 SQL 단편을 생성한다. 레일은 능숙하게 당신이 원하는 정확히 하나의 쿼리 returing를 생산 체인의 다른 모든 SQL 단편을 병합합니다. 연관 수단에 의해 추가하는 방법은 동일한 방식으로 작동한다. 그들이 원활 named_scopes과 통합하는 이유입니다.

    믹스 & 매치하는 이유는 없습니다 작품은 of_sector 방법은 질문 doeso't 작업에 정의 된 동일했다. edited_methods 반환 edited_scope (뿐만 아니라 발견 및 체인의 한 부분으로 불리는 다른 모든 AR의 편리한 메소드)로 체인의 다음 일에 이후 자신의 SQL 조각을 통과 배열. 이 체인의 마지막의 경우는 쿼리를 실행합니다. 마찬가지로,이 중 하나가 작동하지 않습니다.

    @edited = Article.edited_scope
    @edited.recent_scope
    

    이 코드를 사용했습니다. 여기에 그것을 할 수있는 적절한 방법이있다 :

    class User < ActiveRecord::Base
       has_many :articles do
         def of_sector(sector_id)
           find(:all, :conditions => {:sector_id => sector_id})
         end
       end
    end
    

    이 작업을 수행하려면이 기능을 달성하기 위해 :

    class Articles < ActiveRecord::Base
      belongs_to :user
      named_scope :of_sector, lambda do |*sectors|
        { :conditions => {:sector_id => sectors} }
      end
    end
    
    class User < ActiveRecord::Base
      has_many :articles
    end
    

    그럼 당신은 이런 일을 할 수있다 :

    @user.articles.of_sector(4) 
    =>    # articles belonging to @user and sector of 4
    @user.articles.of_sector(5,6) 
    =>    # articles belonging to @user and either sector 4 or 5
    @user.articles.of_sector([1,2,3,]) 
    =>    # articles belonging to @user and either sector 1,2, or 3
    
  3. ==============================

    3.앞서 언급 한 바와 같이, 수행 할 때

    앞서 언급 한 바와 같이, 수행 할 때

    @user.articles.class
    => Array
    

    당신이 실제로 얻을 것은 배열입니다. #class 방법이 아니라도 전에 언급 된 미정 때문이다.

    그러나 당신은 어떻게 user.articles @의 실제 클래스 (프록시해야한다)받을 수 있나요?

    Object.instance_method(:class).bind(@user.articles).call
    => ActiveRecord::Associations::CollectionProxy
    

    그리고 왜 당신은 처음부터 배열을 얻었 는가? #class 방법은 실제 어레이 인 방법 놓치게 통해 CollectionProxy @Target 인스턴스 위임되었으므로. 이 같은 작업을 수행하여 장면 뒤에 엿볼 수 :

    @user.articles.proxy_association
    
  4. ==============================

    4.당신은 협회 (has_one, has_many 등)을 할 때, 액티브에 의해 자동으로 몇 가지 방법을 포함하는 모델을 말한다. 이 협회의 자신을 돌아 인스턴스 메서드를 만들기로 결정 때, 당신은 그 방법의 사용을 할 수 없습니다.

    당신은 협회 (has_one, has_many 등)을 할 때, 액티브에 의해 자동으로 몇 가지 방법을 포함하는 모델을 말한다. 이 협회의 자신을 돌아 인스턴스 메서드를 만들기로 결정 때, 당신은 그 방법의 사용을 할 수 없습니다.

    순서는 다음과 같이이다

    따라서,) = 당신이 연결을 선언 할 때, 그렇지 않으면 수동으로 수행해야합니다 작업의 엄청난 양을 처리 같은 방법이 아름다움 액티브에 의해 자동으로 추가됩니다 분명하다

    당신은 여기에 대한 자세한 내용을보실 수 있습니다 : http://guides.rubyonrails.org/association_basics.html#detailed-association-reference

    ) = 희망이 도움이

  5. from https://stackoverflow.com/questions/1529606/how-do-rails-association-methods-work by cc-by-sa and MIT license