2017-11-16 13 views
0

이름, 주소, 전화 번호 등과 같은 사람과 관련된 속성을 기본 모델 Person으로 만들고 싶습니다. 하나 Person은의 한 광석 더 다음 될 수 있습니다복수 역할을 가진 사람을위한 디자인 패턴

로그인, 비밀번호, LAST_LOGIN에 대한 필드
  • LoginUser ... card_id, last_entrance에 대한 필드
  • CardHolder ...
  • Supplier 그 사람이 공급자인지 여부와 관계없이 깃발이있는 사람
  • Recipient 사람이 수령인이든 아니든간에 깃발이 표시된 경우

상속을 나타 내기위한 Ruby on Rails의 상식이나 모범 사례 디자인 패턴이 있습니까? 모델 및 테이블 구조에서 표현되어야하므로 PersonLoginUser인지 여부를 확인하고 해당 필드에 액세스 할 수 있습니다. 다른 프로젝트에서 나는 STI와 이미 일했지만,이 경우에 이것은 올바른 패턴이 아닙니다.

답변

1

당신이 찾고있는 것은 역 다형성 연관입니다. 다형성 연관을 사용하면 한 모델을 여러 모델에 연결할 수 있습니다. 역 다형성 연관을 사용하면 여러 모델을 하나의 단일 모델로 연결할 수 있습니다. 설정하기가 다소 까다 롭지 만 일단 문제가 발생하면 아무런 문제가 없습니다.

이 작업을 수행하려면 Person 모델과 각기 다른 역할에 대한 중간 역할을하는 다른 모델이 필요합니다. 이 중재 모델은 실제로 다형성 연관이있는 모델입니다. 귀하의 Person 모델은 has_many 모델이며 다양한 롤 모델은 has_one입니다. 그런 다음 :through을 사용하여 코드가 다른 것을 알지 못하게 나머지 연결을 만듭니다. Shazam!

다음은 PersonCardHolder 모델로 수행하는 방법의 예입니다. 나는 여분의 모델을 호출하고있어 Role 그 당연한 선택처럼 보인다 때문에 :

class Person < ApplicationRecord 
    has_many :roles 
    # Reach through the Roles association to get the CardHolders, via polymorphic :rollable. 
    # Unfortunately, you can't has_one, so you'll have to enforce uniqueness in Role 
    # with a validation. 
    has_many :card_holders, through: :roles, source: :rollable, source_type: 'CardHolder' 
end 

class Role < ApplicationRecord 
    belongs_to :person 
    # Here is where our actual polymorphic connection is: 
    belongs_to :rollable, polymorphic: true 
end 

class CardHolder < ApplicationRecord 
    # The other side of the polymorphic connection, with has_one: 
    has_one :role, as: :rollable 
    # Get the person via the role, just like the inverse: 
    has_one :person, through: :role 
end 

데이터베이스 설정은 다음과 같이이다 : 그것은 매우 간단합니다 사용

class CreatePeople < ActiveRecord::Migration[5.1] 
    def change 
    create_table :people do |t| 
     t.string :name 
     # put in whatever other Person columns you need 

     t.timestamps 
    end 
    end 
end 

class CreateRoles < ActiveRecord::Migration[5.1] 
    def change 
    create_table :roles do |t| 
     t.references :person, index: true 
     t.references :rollable, polymorphic: true, index: true 
     t.timestamps 
    end 
    end 
end 

class CreateCardHolders < ActiveRecord::Migration[5.1] 
    def change 
    create_table :card_holders do |t| 
     t.integer :card_id 
     t.datetime :last_entrance 
     # put in whatever other columns you need 

     t.timestamps 
    end 
    end 
end 

:

> p = Person.create(name: "Sven Reuter") 
# directly add a card holder 
> p.card_holders << CardHolder.create(card_id: 1, last_entrance: Time.current) 
# build a role instead 
> p.roles.build(rollable: CardHolder.new(card_id: 2, last_entrance: Time.current) 
# get all of the roles 
> p.roles 
+1

그 매우 똑바로 & 깨끗하게 보입니다, 나는 그것을 시도해 볼 것입니다. 고맙습니다. –

0

저는 Person 테이블과 사람이 가질 수있는 모든 속성의 조합 인 PersonAttributes 테이블로 갈 것입니다. 적용 가능한 경우 PersonAttributes은 STI를 사용할 수 있습니다 (예 : LoginUser은 로그인을 저장하고 CardHolderCard을 참조합니다.

깨끗하고 간단합니다.