2009-06-04 6 views
3

나는 설치 관련 객체의 일반적인 종류의 웹을 시도하고있다. 제가 4 가지 모델을 가지고 있다고 가정 해 봅시다.레일 다형 many to many 연관

  • 예약
  • 영화
  • 태그
  • 내가 할 수 싶습니다

종류는해야 할 일 :

book = Book.find(1) 
book.relations << Tag.find(2) 
book.relations << Category.find(3) 
book.relations #=> [Tag#2, Category#3] 

movie = Movie.find(4) 
movie.relations << book 
movie.relations << Tag.find(5) 
movie.relations #=> [Book#1, Tag#5] 

은 기본적으로 내가 어떤이를 취할 수 있도록하려면 어떤 모델 클래스 (또는 내가 허용하는 모델 클래스)의 객체들 안녕하세요.

분명히 나는 ​​조인 테이블의 엄청난 혼란을 만들고 싶지 않습니다. 이것은 꽤 많은 연관성을 가지고있는 것은 아니지만 꽤 다형성이있는 연관성이 아닌 것처럼 보입니다.

Rails가 연결 선언을 통해 지원할 수있는 것입니까, 아니면 여기에 내 논리를 적용해야합니까?

답변

3

나는 약간의 해결책을 생각해 냈습니다. 그러나 나는 그것이 최선인지 모른다. 그것은 다형성 has_many 통해 가질 수없는 것 같습니다.

그래서 가짜입니다. 그러나 그것은 내가 너무 좋아하는 연합 프록시 마술을 포기하는 것을 의미하며, 그것은 나를 슬프게 만든다. 기본 상태에서는 작동 방식이 다음과 같습니다.

book = Book.find(1) 
book.add_related(Tag.find(2)) 
book.add_related(Category.find(3)) 
book.related  #=> [Tag#2, Category#3] 
book.related(:tags) #=> [Tag#2] 

는 I 번의 has_relations 클래스있어서 어떤 클래스 모델에 추가 될 수있는, 재사용 가능한 모듈을 싸서.

http://gist.github.com/123966

나는 정말 돈 희망; t이 완전히하지만이 작업을 협회 프록시를 다시 구현해야합니다.

0

당신이 설명한대로 정확하게 수행하는 유일한 방법은 조인 테이블이라고 생각합니다. 그래도 6 명이 나쁘지는 않아요. 그리고 당신은 그들을 거의 잊을 수 있습니다.

+0

이 단지를했다 당신이 당신의 항목 테이블 유형을 넣어 있는지 확인 선언 어떤 경우

얼마나 closesly 관련 영화/책에 따라 예. 내 실제 데이터 모델에는 이러한 정확한 내용이 없지만 그 중 많은 부분이 있습니다. 결국이 길로 가면 여럿이 조인 테이블을 보게됩니다. –

+0

Yikes ... 잡았다. 좀 더 생각해 볼게. – fig

7

초기 단계부터 다형성에 대한 지원이 크게 향상되었습니다. 관계 모델 인 모든 모델에 대해 단일 조인 테이블을 사용하여 Rails 2.3에서이 작업을 수행 할 수 있어야합니다.

class Relation 
    belongs_to :owner, :polymorphic => true 
    belongs_to :child_item, :polymorphic => true 
end 

class Book 
    has_many :pwned_relations, :as => :owner, :class_name => 'Relation' 
    has_many :pwning_relations, :as => :child_item, :class_name => 'Relation' 

    # and so on for each type of relation 
    has_many :pwned_movies, :through => :pwned_relations, 
      :source => :child_item, :source_type => 'Movie' 
    has_many :pwning_movies, :through => :pwning_relations, 
      :source => :owner, :source_type => 'Movie' 
end 

이런 종류의 데이터 구조의 결점은 평등 한 쌍이 될 수있는 두 가지 역할을 만들어야한다는 것입니다. 내 책에 대한 모든 관련 영화를보고 싶은 경우에, 나는 함께 세트를 추가해야합니다 :

(pwned_movies + pwning_movies).uniq 

이 문제의 일반적인 예는 소셜 네트워킹 응용 프로그램에서 "친구"관계이다. Insoshi가 사용하는 한 가지 솔루션은 반대 모델을 생성하는 조인 모델 (이 경우 Relation)에 after_create 콜백을 등록하는 것입니다. after_destroy 콜백도 비슷하게 필요하지만 이와 같은 방식으로 일부 추가 DB 스토리지 비용으로 단일 DB 쿼리에 관련된 모든 영화를 얻을 수 있다고 확신 할 수 있습니다.

class Relation 
    after_create do 
    unless Relation.first :conditions => 
     [ 'owner_id = ? and owner_type = ? and child_item_id = ? and child_item_type = ?',  child_item_id, child_item_type, owner_id, owner_type ] 
     Relation.create :owner => child_item, :child_item => owner 
    end 
    end 
end 
0

데시벨 테이블은 당신이

class Items < ActiveRecord::Base 
    has_many :tags 
    has_many :categories 
    has_and_belongs_to_many :related_items, 
     :class => "Items", 
     :join_table => :related_items, 
     :foreign_key => "item_id", 
     :associated_foreign_key => "related_item_id" 
end 

class Books < Items 
class Movies < Items