위임된 유형은 단일 테이블 상속의 대안입니다.

6369 단어 rails
Delegated types은 DHH가 출시되었을 때 많은 관심을 받았습니다.
하지만 많은 분들과의 대화에서 들은 바로는,
나는 그들이 제대로 이해되지 않았다고 생각합니다.
특히 나에 의해.
너무 자주 그들은 다형성 협회 주변의 맛으로 언급됩니다.

위임된 유형을 다형성 연결에 대한 편의 메서드로 볼 수 있지만
DHH의 의도는 상당히 달랐습니다.

API는 다형성 연결에 대한 편의상 이치에 맞지 않습니다.



이제 위임된 유형이 무엇을 제공하는지 살펴보겠습니다.

다른 모델과 다형성 연관이 있는 모델이 주어지면,
위임된 유형을 그대로 선언할 수 있습니다.
의도적으로 "오도된"예부터 시작하겠습니다.

class Recommendation < ApplicationRecord
  delegated_type :recommendable, types: %w[ Wine Winery ]
end


따라서 와인이나 와이너리에 대한 추천이 될 수 있습니다.
이제 다음과 같은 방법에 액세스할 수 있습니다.

Recommendation.wines        # => Recommendation.where(recommendable_type: "Wine")
@recommendation#wine?       # => true when recommendable == "Message"
@recommendation#wine        # => returns the wine record, when recommendable_type == "Wine", otherwise nil
Recommendation.wineries     # => Recommendation.where(entryable_type: "Comment")


좋은 물건.
그러나 이것은 다소 혼란스럽습니다. 한 가지 예를 살펴보겠습니다.
Recommendation.wines는 무엇을 반환합니까? 메서드가 wines 이므로 와인 레코드를 다시 가져올 것으로 기대합니다. 그러나 그것은 일어나는 일이 아닙니다. 대신 와인에 대한 레코드recommendation를 얻습니다.

나는 이 API가 매우 혼란스럽다는 것을 알았다. 그래서 나는 pull request에서 일부 방법에 별칭을 추가할 것을 제안했습니다. Recommendation.for_wines 와 같은 호출을 허용하면 이것이 와인 레코드가 아니라 추천 레코드를 반환한다는 것이 더 분명해집니다.

그래서 여기서 무슨 일이 일어나고 있습니까? 왜 이렇게 혼란스럽습니까?



종종 이름이 궁금하기도 하고, PR에 대해 다른 사람들과 이야기를 하다 보니 깨달은 것이 있습니다. 위임 유형의 의도를 잘못 이해했습니다.

위임된 유형에 대한 documentation에서 발췌:

You can get around the pagination problem by using single table inheritance, but now you're forced into a single mega table with all the attributes from all subclasses. No matter how divergent. If a Message has a subject, but the comment does not, well, now the comment does anyway! So STI works best when there's little divergence between the subclasses and their attributes.



실제로 전체 문서를 읽으면 다형성 연결에 대한 편의가 아닌 위임된 유형을 완전히 소개합니다. 단일 테이블 상속 또는 다중 테이블에 대한 대안으로 제공됩니다.

따라서 함께 나열/조회하려는 개체가 있는 경우 위임된 유형이 좋은 옵션입니다.

따라서 그런 식으로 보면 API와 이름DelegatedType이 훨씬 더 이해되기 시작합니다. Recommendation.winesreccomendations 테이블의 레코드를 반환하지만 이는 와인에 대한 추천이 와인 유형이고 위임된 유형이 와인이라고 잘못 선언했기 때문입니다.

좀 더 합리적인 예를 보여주면 훨씬 더 이해가 잘 될 것입니다.

적절한 예



class Product
    delegated_type :purchasable, types: %w[Wine Bundle Voucher]
end

와인, 와인 묶음, 바우처를 판매하는 상점을 짓는다고 가정해 보겠습니다. 우리는 실제로 하나의 테이블에서 쿼리하고 페이지를 매길 수 있기를 원하지만 속성 측면에서 매우 다양하므로 STI(단일 테이블 상속)는 훌륭한 솔루션이 아닙니다.

위임된 유형이 들어오는 곳입니다. product_number, 가격, 재고, 게시와 같은 제품 테이블의 공유 속성을 가질 수 있습니다. 그러나 특정 테이블에 필요한 모든 속성을 가질 수도 있습니다. 번들에는 여러 와인이 연결되어 있습니다…

따라서 위임된 유형의 경우 wine 레코드를 products 테이블과 wines 테이블의 "조인된 행"으로 간주합니다.

제품wine에서 알아야 할 모든 것은 제품 레코드 또는 위임된 유형에서 얻습니다. 따라서 이름은… 실제로 와인 테이블에서만 레코드를 인스턴스화하지 않는 것입니다.

class Product < ApplicationRecord
  delegated_type :purchasable, types: %w[Wine Bundle Voucher]
  delegate :display_name, to: :purchasable
end

class Wine < ApplicationRecord
  def display_name
    name + vintage
  end
end

class Bundle < ApplicationRecord
  has_many :wines

  def display_name
    "#{name} (#{wines.count} wines)"
  end
end

class Voucher
  def display_name
    "#{amount}$ Voucher"
  end
end


따라서 제품에 대한 일부 측면과 위임된 유형에 대한 보다 구체적인 측면이 있습니다. OOP 다형성을 활용하고 STI보다 훨씬 더 유연하게 사용할 수 있습니다.

따라서 위임된 유형은 하나의 테이블에 무언가를 저장하고 싶을 때 강력한 도구가 될 수 있으므로 쉽게 쿼리할 수 있고 때로는 더 중요하게는 페이지 매김을 사용할 수 있습니다.

rstuder.ch에 처음 게시됨

좋은 웹페이지 즐겨찾기