2009-11-23 2 views
0

나는 손을 올려야하고, 나는 이걸 완전히 뒤 졌다고 선언해야한다!has_many의 속성으로 찾기

나는 다음과 같은 모델이 있습니다

Chat: 
    has_many :messages 

Message: 
    belongs_to :chat, :counter_cache => true 
    belongs_to :authorable, :polymorphic => true 

User: 
    has_many :messages, :as => :authorable 
    has_many :chats, :through => :messages, :uniq => true 

Guest: 
    has_many :messages, :as => :authorable 

내가 어디에 답이 a로 게시하는 채팅의 모든 메시지가없는 의미 (나에게 "답"채팅을 제공하기 위해 채팅에 named_scope를 작성하려고 해요을 사용자) - 지금까지 나는 많은 서클에서 만날 수있었습니다!

어떤 도움이 매우 많이 감사하겠습니다! 그것은 쉽게 (또는 가능!)

감사합니다, 애쉬

답변

3

의 핵심은 그들이 돌아갑니다 모델에 배치하는 것입니다. 응답되지 않은 채팅을 받으려면 이름이 지정된 범위가 채팅 모델에 있어야합니다. 불행히도 협회가 비어있는 경우를 찾으면 쉽게 알 수 없습니다.

명명 된 범위로 수행하려면 LEFT/RIGHT OUTER 조인과 GROUP_BY 연산자가 필요합니다. 그것은 예쁘지 않을 것이고 자신의 SQL을 작성하는 것보다 낫지 않습니다.

카운터 캐시를 사용하는 것이 더 쉬울 수도 있습니다. 그러나 다형성 연관은 직선 카운터 캐시가 작동하지 않을 수도 있음을 의미합니다.

이 문제는 답이 채팅은 그렇게도하거나 그 사용자와 메시지가없는 경우 (메시지 채팅 손님 만 작성에 상관 메시지를 가진 사람들은 여전히 ​​답이없는 것으로 간주되어, 조금 불분명?

그것보다 이전의 경우 할 것입니다 간단한 카운터 캐시, 다른 하나는 현명한 당신이 할 수있는 좀 더 작업을해야합니다

공통 코드를 두 경우 모두에 대해 :.

이 마이그레이션 MESSAGE_COUNT라는 채팅 테이블에 열을 추가

class AddCounterCache < ActiveRecord::Migration 
    def self.up 
    add_column :chats, :message_count, :integer, :default => 0 
    end 

    def self.down 
    remove_column :chats, :message_count 
    end 
end 

그런 다음 채팅 모델에서 명명 된 범위를 만듭니다.

class Chat < ActiveRecord::Base 
    ... 
    named_scope :unanswered, :conditions => {:message_count => 0} 
end 

답이없는 채팅이 0 메시지

class Message < ActiveRecord::Base 
    belongs_to :chat, :counter_cache => true 
end 

답이없는 채팅 손님에 의해 작성된 메시지를 가질 수있는 경우에 대한 고유 코드가있는 경우에 대한 고유 코드가 아니라 사용자 :

특정 상황에서만 카운터 캐시를 업데이트하기를 원하므로 ActiveRecord가 카운터 캐시를 증가시키는 데 사용하는 방법을 재정의해야합니다. 그래서 우리는 그것을 원할 때만 움직입니다. Rails는 메서드의 이름을 바꾸고 다른 메서드로 래핑하는 편리한 방법을 ActiveSupport's alias_method_chain을 통해 제공합니다. 따라서이 코드는 필요한 경우에만 카운터 캐시를 업데이트하는 데 사용되는 기존 메서드를 트리거하는 새로운 메서드를 만듭니다. 그런 다음 alias_method_chain을 사용하여 메서드의 이름을 변경하면 ActiveRecord에서 제공하는 메서드 대신 새 메서드가 호출됩니다.

class Message < ActiveRecord::Base 
    belongs_to :chat, :counter_cache => true 

    def belongs_to_counter_cache_after_create_for_chat_with_users_only 
    if authorable_type == "User" 
     belongs_to_counter_cache_after_create_for_chat_without_users_only 
    end 
    end 

    def belongs_to_counter_cache_before_destroy_for_chat_with_users_only 
    if authorable_type == "User" 
     belongs_to_counter_cache_before_destroy_for_chat_without_users_only 
    end 
    end 

    alias_method_chain :belongs_to_counter_cache_before_destroy_for_chat, :users_only 
    alias_method_chain :belongs_to_counter_cache_after_create_for_chat, :users_only 

end 

모든 작업이 완료되었습니다. Chat.unanswered은 귀하의 기준에 맞는 모든 채팅을 나열합니다. 또한 채팅에서 메시지 수를 가져 오려면 두 번째 쿼리가 필요하지 않은 보너스를받습니다.

+0

와우 ... 왜 내가 어디로 가지 않았는지 확실히 설명합니다. 나는 당신의 레일 스킬에 굴복합니다! 나는 오늘 밤에 그것에게 줄 것이다 - 감사합니다. Fwiw a Chat은 사용자가 0 개의 게시물을 가지고있을 때 답변을 얻지 못합니다. 게스트 게시물은 몇 개라도 가질 수 있지만 사용자가 게시물을 하나 이상 가져올 때까지 답이없는 것으로 간주됩니다. – Ash

+0

당신이 여기에서하고 있었던 것에 대해 머리를 쓰려면 잠시 시간이 걸렸습니다. -하지만 지금은 이해하고 있습니다. 감사! – Ash

+0

고급 코드가 목표를 달성하는 방법을 더 잘 설명 할 수 있었을 것 같습니다. 나는 앞으로 비슷한 문제가있는 사람들을 위해 솔루션을 업데이트 할 것입니다. – EmFi

1

당신이 has_many 모델 자체에 named_scope을 정의 할 수 있습니다 경우 FWIW 나는 특히 명명 된 범위 인에 연결된 아니에요.

Chat.messages.unanswered 

또는, 당신은 당신이 Chat.unanswered을 할 수 있도록 SQL에서 named_scope을 쓸 수 있지만, 나에게 잘못된 API 것 같은 느낌이 든다.

더 많은 예제 : 명명 된 범위에 http://blog.peelmeagrape.net/2008/6/21/named_scope-is-super-awsome-with-has_many

관련 문제